Připojení k více databázím zároveň

DrakMC
Člen | 35
+
0
-

Ahoj, potřeboval bych pracovat s více databázemi zároveň. Jak toho docílím? Našel jsem již řešené téma, ale je již 3 roky staré. https://forum.nette.org/…azi-najednou

nightfish
Člen | 472
+
+3
-

@DrakMC Docílíš toho tak, jak je popsáno ve 3 roky starém vlákně. A nebo třeba dle https://forum.nette.org/…uhe-databazi#…

Zkus popsat, k čemu ta dvě databázová spojení vlastně potřebuješ, možná existuje nějaké jiné řešení tvého problému.

DrakMC
Člen | 35
+
0
-

nightfish napsal(a):

@DrakMC Docílíš toho tak, jak je popsáno ve 3 roky starém vlákně. A nebo třeba dle https://forum.nette.org/…uhe-databazi#…

Zkus popsat, k čemu ta dvě databázová spojení vlastně potřebuješ, možná existuje nějaké jiné řešení tvého problému.

Díky za radu. :)

Vyzkoušel jsem to, ale bohužel to nefunguje. Zobrazuje to chybovou hlášku: https://i.imgur.com/cO4Vpkt.png

DatabaseAccessor.php
Mám ho v App\Model – je to dobré umístění? Případně jaké je lepší?

<?php

namespace App\Model;

interface DatabaseAccessor {
    function get($name): \Nette\Database\Context;
}

TestPresenter.php

<?php

namespace App\Presenters;

use App\Model\DatabaseAccessor;
use Nette;

final class TestPresenter extends Nette\Application\UI\Presenter {
    /** @var DatabaseAccessor @inject */
    public $databaseAccessor;

    public function renderDefault(): void {
        $db = $this->databaseAccessor->get("db1");
    }
}

services.neon

services:
	- App\Router\RouterFactory::createRouter
	- App\Model\DatabaseAccessor(
	    db1: @database.db1.context
	)

local.neon

parameters:


database:
    db1:
        dsn: 'mysql:host=127.0.0.1;dbname=databaze'
        user: uzivatel
        password: heslo
Marek Bartoš
Nette Blogger | 1167
+
+1
-

On ten interface v Nette 3 vypadá jinak

namespace App\Model;

use Nette\Database\Context;

interface ContextLocator
{
	public function getDb1(): Context;

	public function getDb2(): Context;
}
services:
	- App\Model\ContextLocator(a: @database.db1.context, b: @database.db2.context)

https://github.com/…orMulti.phpt

Editoval Marek Bartoš (30. 12. 2021 1:56)

Marek Bartoš
Nette Blogger | 1167
+
+1
-

Případně můžeš vyžadovat přímo Context, autowiring mít zapnutý jen pro hlavní databázi a službu s připojením pro další databázi do služeb předávat manuálně

database:
	primary:
		dsn: 'mysql:host=127.0.0.1;dbname=databaze'
		user: uzivatel
		password: heslo

	backlog:
		dsn: 'mysql:host=127.0.0.1;dbname=databaze'
		user: uzivatel
		password: heslo
		autowired: false

services:
	- App\Example\Service(@database.backlog.context)
namespace App\Example;

use Nette\Database\Context;

class Service
{
	public function __construct(private Context $context)
	{
	}
}

Editoval Marek Bartoš (30. 12. 2021 1:54)

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

On ten interface v Nette 3 vypadá jinak

namespace App\Model;

use Nette\Database\Context;

interface ContextLocator
{
	public function getDb1(): Context;

	public function getDb2(): Context;
}
services:
	- App\Model\ContextLocator(a: @database.db1.context, b: @database.db2.context)

https://github.com/…orMulti.phpt

Díky za rychlou odpověď. Nyní mi to zobrazuje tuto chybovou hlášku: https://i.imgur.com/NI1TuZ9.png

Marek Bartoš
Nette Blogger | 1167
+
0
-

Můžeš sem dát celý kód tvého locatoru a jak jej registruješ? Podle testů bych to měl mít imho správně.

Tipnu si: Nette si myslí, že chceš zapsat accessor a ne locator. Accessor může mít jen jednu metodu nazvanou get(), ty tam máš i další. Pojmenuj všechny metody getSomething(), ne jen get()

Editoval Marek Bartoš (30. 12. 2021 2:25)

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

Můžeš sem dát celý kód tvého locatoru a jak jej registruješ? Podle testů bych to měl mít imho správně.

Tipnu si: Nette si myslí, že chceš zapsat accessor a ne locator. Accessor může mít jen jednu metodu nazvanou get(), ty tam máš i další. Pojmenuj všechny metody getSomething(), ne jen get()

ContextLocator.php

<?php

namespace App\Model;

use Nette\Database\Context;

interface ContextLocator {
    public function getDb1(): Context;
}

services.neon

services:
	- App\Router\RouterFactory::createRouter
	- App\Model\ContextLocator(db1: @database.db1.context)
DrakMC
Člen | 35
+
0
-

Ještě přidávám, jak vypadá můj TestPresenter.php:

<?php

namespace App\Presenters;

use App\Model\ContextLocator;
use Nette;

final class TestPresenter extends Nette\Application\UI\Presenter {
    /* @var \App\Model\ContextLocator @inject */
    public $contextLocator;

    public function renderDefault(): void {
        $db = $this->contextLocator->getDb1();
    }
}
Marek Bartoš
Nette Blogger | 1167
+
+1
-

Zkus přidat druhou metodu, možná to nepředpokládá, že by byla jen jedna. Jinak to máš imho správně

DrakMC
Člen | 35
+
0
-

Bylo to tím – již to funguje. Díky!

Nicméně se mi zobrazil další error: https://i.imgur.com/lXEjvH2.png

Editoval DrakMC (30. 12. 2021 15:57)

Marek Bartoš
Nette Blogger | 1167
+
-1
-

Nepředává se ti služba. Rozepiš var a inject anotace na více řádků, inline může být jen jedna.

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

Nepředává se ti služba. Rozepiš var a inject anotace na více řádků, inline může být jen jedna.

Myslíš pro každou databázi zvlášť? Jak? Mohl bys mi prosím ukázat příklad?

Marek Bartoš
Nette Blogger | 1167
+
-1
-
/**
 * @var \App\Model\ContextLocator
 * @inject
 */
public $contextLocator;

Ideálně si ale službu předej v konstruktoru. Mimo base presentery se spoustou závislostí je inject imho zbytečný.

Editoval Marek Bartoš (30. 12. 2021 16:52)

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

/**
 * @var \App\Model\ContextLocator
 * @inject
 */
public $contextLocator;

Ideálně si ale službu předej v konstruktoru. Mimo base presentery se spoustou závislostí je inject imho zbytečný.

Zobrazil se mi tento error: https://i.imgur.com/81NvmdE.png

Je to tím, že ho nemám přidaný v konstruktoru?

Marek Bartoš
Nette Blogger | 1167
+
0
-

Těžko říct, když nevidím kód

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

Těžko říct, když nevidím kód

Promiň, zasílám ho. :)

TestPresenter.php

<?php

namespace App\Presenters;

use App\Model\ContextLocator;
use Nette;

final class TestPresenter extends Nette\Application\UI\Presenter {
    /**
     * @var ContextLocator
     * @inject
     */
    public $contextLocator;

    public function renderDefault(): void {
        $db = $this->contextLocator->getDb1();
    }
}

ContextLocator.php

<?php

namespace App\Model;

use Nette\Database\Context;

interface ContextLocator {
    public function getDb1(): Context;

    public function getDb2(): Context;
}

services.neon

services:
	- App\Router\RouterFactory::createRouter
	- App\Model\ContextLocator(db1: @database.db1.context, db2: @database.db2.context)
Marek Bartoš
Nette Blogger | 1167
+
0
-

A služby database.db1.context a database.db2.context existují?

DrakMC
Člen | 35
+
0
-

Ano, existují:

local.neon:

parameters:


database:
    db1:
        dsn: 'mysql:host=127.0.0.1;dbname=databaze'
        user: uzivatel
        password: heslo
    db2:
        dsn: 'mysql:host=127.0.0.1;dbname=databaze'
        user: uzivatel
        password: heslo
Marek Bartoš
Nette Blogger | 1167
+
0
-

Zkus sem do LocatorDefinition přidat následující a poslat co ti to vypíše

bdump($name);
bdump($this->references);

Editoval Marek Bartoš (30. 12. 2021 17:29)

DrakMC
Člen | 35
+
0
-

Otevřel jsem soubor LocatorDefinition.php ve /vendor/nette/di/src/DI/Definitions a přidal

bdump($name);
bdump($this->references);

Upravený LocatorDefinition.php: https://i.imgur.com/eYJWa7B.png

Domnívám se, že se nic nezměnilo a ukazuje to stejnou chybovou hlášku: https://i.imgur.com/xRTJyXY.png

Marek Bartoš
Nette Blogger | 1167
+
0
-

Smaž vygenerovaný kontejner, jinak se ten kód nespustí.

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

Smaž vygenerovaný kontejner, jinak se ten kód nespustí.

Kde ho naleznu? Zkoušel jsem promazávat /temp/cache/.

Marek Bartoš
Nette Blogger | 1167
+
0
-

To je správně. Cesta k vygenerovanému kontejneru je vidět v poslední výjimce co jsi posílal. Určitě edituješ správný soubor? Jinde se stejný text výjimky nepoužívá, jestliže se spouští tak by bdump() měl též.

DrakMC
Člen | 35
+
0
-

Marek Bartoš napsal(a):

To je správně. Cesta k vygenerovanému kontejneru je vidět v poslední výjimce co jsi posílal. Určitě edituješ správný soubor? Jinde se stejný text výjimky nepoužívá, jestliže se spouští tak by bdump() měl též.

Editoval jsem soubor LocatorDefinition.php v /vendor/nette/di/src/DI/Definitions

Editoval DrakMC (30. 12. 2021 21:01)

David Grudl
Nette Core | 8129
+
0
-

@DrakMC měl jsi to od začátku dobře, jen místo /* @var \App\Model\ContextLocator @inject */ musí být /** @var \App\Model\ContextLocator @inject */, ta hvězdička je podstatná, jinak PHP takový komentář zahodí a Nette se nemá jak dozvědět, že tam byl.