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)