Připojení k nově vytvořené databázi

- mrudolf
 - Člen | 7
 
Zdravím všechny,
řeším následující problém. V rámci skriptu vytvářím novou databázi a potřebuji získat objekt Context, který by mi umožnil s touto databází dále pracovat.
config.neon
<?php
database:
    default:
        dsn:          "mysql:host=127.0.0.1;dbname=db_zakladni"
        user:         "dbuzivatel"
        password:     "dbheslo"
        options:      [PDO::MYSQL_ATTR_COMPRESS = true]
        debugger:     true        # debugger bar panel
        explain:      true        # explain queries in debugger bar
        conventions:  discovered  # or static or name of your class, default is discovered
        autowired:    true
        #lazy: yes
?>
v BasePresenteru se dostanu ke spojení k základní databázi přes:
<?php
	/** @var Nette\Database\Context @inject */
	public $dbConnection;
?>
Pomocí $dbConnection vytvořím novou databázi, chtěl jsem poté inicializovat nový Context:
<?php
protected function getNewDBConnection($db_server, $db_name){
   $connection = new Nette\Database\Connection("mysql:host=".$db_server.";dbname=".$db_name, ?, ?);
   $context = new Nette\Database\Context($connection, ?);
   return $context;
}
?>
zde jsem narazil.
- Jak mohu získat údaje z konfiguračního souboru pro Connection (přihlašovací údaje jsou stejné k oběma databázím, kromě jména databáze)
 - Při inicializaci Nette\Database\Context je vyžadován druhý parametr IStructure, který není zdokumentovaný na webu. Jaký mám použít?
 

- CZechBoY
 - Člen | 3608
 
Udělal bych si nějakou ContextFactory, který bych předal jen jméno
databáze a všechno by mi zařídila sama.
nedávno jsem nějakou takovou ukázku psal
https://forum.nette.org/…ez-je-v-neon#…

- mrudolf
 - Člen | 7
 
Uznávám že nejsem v Nette až tak znalý, práce s databází přes Context mi ale vyhovuje. Factory jsem zkopíroval z tvého příspěvku, na to, jak jí propojit s konfiguračním souborem přes službu jsem ale nepřišel.
Uvažuji tedy o přímějším způsobu, v Base presenteru si třídu Connection a Context vytvořit ručně, cca:
<?php
function ($db_number){
	$db_config = ? // (získání dat z config.local.neon)
	$connection = new Nette\Database\Connection("mysql:host=$db_config['host'];dbname=mojedb_".$db_number, $db_config['user'], $db_config['password']);
	$context = new Nette\Database\Context($connection, ?);
	return $context;
}
?>
K tomu jsou ale potřeba 2 věci:
- Existuje nějaký snadný způsob, jak se z Presenteru dostat k hodnotám z konfiguračního souboru pro přihlašovací údaje?
 
řekněme kód v configuračním souboru:
<?php
parameters:
    database:
		host:		  "127.0.0.1"
        user:         "dbuzivatel"
        password:     "dbheslo"
?>
- způsob vytvoření Contextu jsem našel na https://doc.nette.org/cs/database , kód ale nefunguje:
 
<?php
new Nette\Database\Context($connection);
?>
Context vyžaduje druhý parametr, kterým je IStructure (Structure). Ta na oplátku potřebuje Nette\Caching\IStorage. Jak tyto mohu na úrovni presenteru získat?

- mrudolf
 - Člen | 7
 
Službu jsem zaregistroval, databázi se mi do ní dostat nepodařilo.
Dohledal jsem nakonec, jak inicializovat nový kontext v Presenteru:
<?php
	/**
	 * @inject
	 * @var Nette\Caching\IStorage
	 */
	public $cache;
	function dbConn ($db_number){
    	$db_config = ['host'=>'127.0.0.1', 'user'=>'', 'password'=>''];
		$connection = new Nette\Database\Connection("mysql:host=$db_config['host'];dbname=mojedb_".$db_number, $db_config['user'], $db_config['password']);
		$structure = new Nette\Database\Structure($connection, $this->cache);
		$context = new Nette\Database\Context($connection, $structure);
	    return $context;
	}
?>
Snad se mi ještě podaří dostat parametry spojení z configu…

- CZechBoY
 - Člen | 3608
 
Dej si přihlašovací údaje k databázi jako parametry, který si potom předáš do té ContextFactory (trošku upravíš tu třídu ještě, aby se nedávaly parametry do create metody, ale do konstruktoru).
parameters:
	db_user: abc
	db_password: abc
	db_host: localhost
database:
	dsn: "mysql:host=%db_host%;dbname=abc"
	user: %db_user%
	password: %db_password%
services:
	- App\ContextFactory(%db_user%, %db_password%, %db_host%, ...)
use Nette\Database\Connection;
use Nette\Database\Context;
use Nette\Database\IConventions;
use Nette\Database\IStructure;
use Nette\Caching\IStorage;
class ContextFactory
{
	private $dbUser;
	private $dbPwd;
	private $dbHost;
	private $structure;
	private $conventions;
	private $cacheStorage;
    public function __construct($dbUser, $dbPwd, $dbHost, IStructure $structure = null, IConventions $conventions = null, IStorage $cacheStorage = null)
    {
		$this->dbUser = $dbUser;
		$this->dbPwd = $dbPwd;
		$this->dbHost = $dbHost;
        $this->structure = $structure;
        $this->conventions = $conventions;
        $this->cacheStorage = $cacheStorage;
    }
    /**
     * @return Context
     */
    public function create($db, array $options = null)
    {
		$dsn = 'mysql:host=' . $this->dbHost . ';dbname=' . $db;
        $connection = new Connection($dsn, $this->dbUser, $this->dbPwd, $options);
        return new Context($connection, $this->structure, $this->conventions, $this->cacheStorage);
    }
}
					Editoval CZechBoY (27. 9. 2016 18:04)

- mrudolf
 - Člen | 7
 
- Pro manipulaci s jinou DB je potřeba znovu inicializovat Structure a Conventions, jinak si pak Context stěžuje, že tabulky neexistují. Takže jsem v ContextFactory nakonec skončil s:
 
<?php
   public function create($db, array $options = null)
    {
        $dsn = 'mysql:host=' . $this->dbHost . ';dbname=' . $db;
        $connection = new Connection($dsn, $this->dbUser, $this->dbPwd, $options);
    	$structure = new Structure($connection, $this->cacheStorage);
		$conventions = new DiscoveredConventions($structure);
        return new Context($connection, $structure, $conventions, $this->cacheStorage);
    }
?>
Vše zatím vypadá funkční.