Database substitutions – fungujú?

- uestla
- Backer | 799
Leda si pro service nastavit jednoduchou továrničku, které pak předat prefixy nastavené na jiném místě konfigurace…
config.neon:
common:
services:
database:
factory: [FactoryContainer, createDatabaseService]
arguments:
dsn: 'mysql:host=localhost;dbname=test'
username: 'user'
password: 'password'
prefixes: %prefixes%
prefixes:
prefix: my_super_prefix_
prefix2: even_superer_prefix_
FactoryContainer.php
class FactoryContainer
{
public static function createDatabaseService($container, $dsn, $username, $password, array $prefixes = NULL)
{
$connection = new Nette\Database\Connection($dsn, $username, $password);
$connection->substitutions = (array) $prefixes;
return $connection;
}
}
Třeba nějak takhle…
Pak již průšvihem není používati
$container->database->query("SELECT * FROM [:prefix:table] ...");

- uestla
- Backer | 799
Do onoho factory: ... se předává callback, čili to, co se
zavolá, když se bude chtít service vytvořit. Nic ti nebrání v tom, mít
všechny v jedné třídě, sám to tu popisuješ. Každá továrnička
vytváří service, čili struktura configu je následující:
common:
services:
service1:
factory: [BaseModel, createService1]
service2:
factory: [BaseModel, createService2]
database:
factory: [BaseModel, createDatabaseService]
arguments: ...
# jak si služby nazveš, je na tobě, pak je ale nezapomeň pod stejným názvem vytahovat

- Peppy
- Člen | 137
No tak som z toho ešte väčší debil, jak som mohol byť (ani nie tak z tých továrničiek a tried, ako z neon-u), mám neon:
common:
services:
robotLoader:
run: true
database:
factory: [BaseModel, createDatabaseService]
arguments: ['%database%']
# ['mysql:host=localhost;dbname=cmsdb', 'root', '']
model:
class: Model
arguments: ["@database"]
authenticator:
factory: [BaseModel, createAuthenticatorService]
website:
style: default
production < common:
database:
type: mysql
hostname: localhost
username: root
password: ''
dbname: cmsdb
prefixes:
prefix: cms_
suffix:
development < common:
database:
type: mysql
hostname: localhost
username: root
password: ''
dbname: cmsdb
prefixes:
prefix: cms_
suffix:
console < common:
Ako sa dostať z common:services:database dáta, ktoré sú dole
(development < common)? A navyše, je tam nutný ten service
model? Vytvára objekt BaseModel, ako som logicky vyvodil. Nette
vyhodilo InvalidStateException (Parameter ‚database‘ is not scalar). Ale
mám definovanú továrničku:
public static function createDatabaseService($container, $type, $hostname,
$database, $username, $password,
$prefixes = array())
{
...
}
Editoval Peppy (10. 7. 2011 19:08)

- uestla
- Backer | 799
Teď to nevzdávej, jsme skoro u cíle!
V ukázaném configu máš pro všechna prostředí (tj. sekce
common) nadefinovány 4 services a 1 vlastní položku website.
services je speciální rezervovaný klíč. Service
model nevytváří tebou psanou instanci BaseModel,
nýbrž instanci třídy Model. Konstruktoru třídy
Model předává service database (to se značí
zavináčem na začátku, za @database si tedy dosaď
services.database).
Co se týče továrničky pro database service, tak té
normálně můžeš v configu předat %database%, je nutné ho pak
ale mít definovaný – pokud jsi v development režimu, pak je samozřejmě
musíš mít v sekci development, v produkčním režimu zase
v sekci production, nebo jsou-li údaje stejné pro všechna
prostředí, můžeš to fláknout do sekce common.
Onu výjimku to vyhazuje když žádáš o serivce database
nebo model?
- koukni, jak k chybě došlo, klidně použij překladač na chybové hlášky, neboj se toho
- zkoušej si dumpovat načtený konfig
(
dump($container->params); die();v bootstrapu)

- uestla
- Backer | 799
Poněvadž a protože ty tím předáváš následující:
array(
array(
'type' => 'mysql',
'hostname' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'cmsdb',
'prefixes' => array(
'prefix' => 'cms_',
'suffix' => '',
),
)
)
Čili bych skromně poradil upravit na:
factory: [BaseModel, createServiceDatabase]
arguments: %database%
EDIT:
Ono totiž %database% už je pole, není třeba ho umisťovat
do pole…
Editoval uestla (10. 7. 2011 20:16)

- Peppy
- Člen | 137
A ďalšia chyba: array_map(): Argument #2 should be an array
… Tak sa mi zdá, že to musím buď predefinovať v argumentoch (1 argument
= array) alebo to nastaviť v neone a nepredávať funkcii/metóde pole…asi
by som bral druhú možnosť – nastaviť to v neone. To znamená, mám
preddefinovanú funkciu:
public static function createDatabaseService($container, $type, $hostname,
$database, $username, $password,
$prefixes = array())
Tým si myslím, žeby bolo prínosnejšie v neone niečo také:
arguments: [%database.type%, %database.hostname%, %database.username%, ...]
Ak to teda neon podporuje…
EDIT:
Keď som to takto upravil, hlási InvalidStateException:
Missing item 'type' …
Editoval Peppy (10. 7. 2011 20:32)

- uestla
- Backer | 799
EDIT 2:
Tak jsem již přišel na funkční řešení, a sice:
common:
services:
database:
factory: [BaseModel, createServiceDatabase]
arguments:
- %database% # tady je řešení probíraného problému
database:
type: 'mysql'
hostname: 'localhost'
dbname: 'cmsdb'
prefixes:
prefix: 'cms_'
suffix:
production < common:
database:
username: 'prod_username'
password: 'prod_password'
development < common:
database:
username: 'root'
password: ''
# ...
Využívá jak výše probíraný problém předání jiných argumentů
v jiných prostředí (common, development, …)
dokonce s tím, že data v common se „spojují“
s upřesňujícími v konkrétních ostatních větvích (tj. že je
nepřepisují, ale mergují).
Editoval uestla (20. 7. 2011 23:02)

- Peppy
- Člen | 137
Ehm. Aj tak to nepracuje tak, ako by to teoreticky malo:
InvalidStateException (parameter ‚database‘ is not a scalar.)
Call Stack:
$factory = $container->getService('database');
NEON:
common:
php: # PHP configuration
date.timezone: Europe/Prague
# session.save_path: "%tempDir%/sessions"
# zlib.output_compression: yes
services:
robotLoader:
run: true
factories:
class: FactoryModel
authenticator:
factory: ["@factories", createAuthenticatorService]
database:
factory: ["@factories", createDatabaseService]
arguments:
- %database%
model:
class: BaseModel
arguments: ["@factories"]
database:
type: mysql
production < common:
database:
type: mysql
username: root
password:
hostname: localhost
database: cmsdb
prefixes:
prefix:
suffix:

- Peppy
- Člen | 137
Teda je to zložitejšie…Ak dám [%database%], tak je to táto
správa:
Presnejšie, hodí to exceptionm v Container.php:
251: $that = $this;
252: return @preg_replace_callback('#%([a-z0-9._-]*)%#i', function ($m) use ($that) { // intentionally @ due PHP bug #39257
253: list(, $param) = $m;
254: if ($param === '') {
255: return '%';
256: } elseif (!is_scalar($val = Nette\Utils\Arrays::get((array) $that->params, explode('.', $param)))) {
257: throw new Nette\InvalidStateException("Parameter '$param' is not scalar."); /* <= Tu. */
258: }
259: return $val;
Ak len %database%, tak to hodí warning: „array_map():
Argument #2 should be an array.“. Tak ako teraz? Skalár alebo Array??
Editoval Peppy (4. 8. 2011 14:56)