programming on an interface, not an implementation

gregor_nette
Member | 13
+
0
-

Hi,
I try to achieve something like exchanging database connection by using an interface for a presenter and defining the implemention elsewhere. By this I want to be able to exchange the implementation without touching the presenter

My current idea is the following setup.
IArticleFacade is the Interface, DibiArticleFacade is the implementation and somehow there is a connection telling ArticlelistPresenter to use DibiArticleFacade.

IArticleFacade.php:

<?php

namespace App\Model;

interface IArticleFacade {
    public function getHomepageArticle();
    public function getPublicArticles();
    public function getArticle(string $artnr);
}

DibiArticleFacade.php:

<?php
namespace App\Model;

use Dibi;

final class DibiArticleFacade implements IArticleFacade{

    private Dibi\Connection $database;
    public function __construct(Dibi\Connection $database) {
        $this->database = $database;
    }
    public function getPublicArticles() {
        return $this->database->query('SELECT * FROM artikel %lmt', 10)->fetchAll(); //
    }
    public function getHomepageArticle() {
        return $this->database->query('SELECT * FROM artikel WHERE sk1 = "1" %lmt', 10)->fetchAll(); //
    }
    public function getArticle(string $artnr) {
        return $this->database->query('SELECT * FROM artikel WHERE artnr = ?', $artnr)->fetch(); //
    }
}

and the presenter is something like

<?php
declare(strict_types = 1)
    ;
namespace App\Presenters;

use App\Model\IArticleFacade;
use Nette;

final class ArticlelistPresenter extends Nette\Application\UI\Presenter {
    private IArticleFacade $facade;
    public function __construct(IArticleFacade $facade) {
        $this->facade = $facade;
    }
    public function renderDefault(): void {
        $this->template->posts = $this->facade->getPublicArticles();
    }
}

How do I achieve that?

If my question is unclear or you need some more details, leave a comment. I'm starting with nette…

Thank you very much

Artify
Member | 2
+
0
-

Hi
Where’s the problem? Dependency injection?

gregor_nette
Member | 13
+
0
-

Hi,
I guess so… WHERE do I define the implementation?
Is it in something like local.neon ??? Can you point me to an example?

extensions:
    dibi: Dibi\Bridges\Nette\DibiExtension22

dibi:
   host: 'localhost'
   username:
   password:
   database: test
   lazy: true
....

services.neon:

services:
    - App\Router\RouterFactory::createRouter
    - App\Model\DibiArticleFacade

How do I tell the presenter to use dibi?
Do you have a link to the corresponding docs?

Last edited by gregor_nette (2021-11-03 16:16)

gregor_nette
Member | 13
+
0
-

Ok…
to answer my questiton: This works.

I have most likely a different problem, but THAT part seems to work fine.

Milo
Nette Core | 1283
+
+2
-

Yes, you register services in NEON file. But the local.neon is mostly used only for database configuration and similar. It's different for production and developent. You can use common.neon or any else loaded by configurator.

About doc – probably DI autowiring chapter – https://doc.nette.org/…n/autowiring

If you register DibiArticleFacade as the only IArticleFacade implementation, it will be injected into presenter. But if you want to inject specific implementation, just change presenter's constructor signature to DibiArticleFacade $facade and DI container will choose this one.

If you register more than one IArticleFacade services implementation, autowiring for IArticleFacade typehint will stop work. You can disable autowiring for the one of IArticleFacade. Or, you can specify injected service manually, like:

services:
	- App\Presenters\ArticlelistPresenter(facade: DibiArticleFacade)