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

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mrudolf
Člen | 7
+
0
-

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
+
+1
-

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
+
0
-

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"
?>
<?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?

CZechBoY
Člen | 3608
+
0
-

Službu zaregistruješ takhle:

services:
	- App\ContextFactory
mrudolf
Člen | 7
+
0
-

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
+
+2
-

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
+
0
-

Děkuju za pomoc, funguje perfektně.

mrudolf
Člen | 7
+
+2
-
  • 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í.