Database substitutions – fungujú?

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

Funguje toto:

$this->database->substitution['prefix'] = 'my_super_prefix_';

? Pracuje sa pomocou dvojbodiek (ako v Dibi?)…
A ak áno, ako ich nastaviť v neone?

Editoval Peppy (8. 7. 2011 19:48)

Peppy
Člen | 137
+
0
-

Nerád upozorňujem sám na seba na to aby som dostal odpoveď, ale urobím to. Skúšal to niekto?

uestla
Backer | 799
+
0
-

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] ...");
Peppy
Člen | 137
+
0
-

Oukej, Hneď to využijem. Díky. Takže, NotORM (Nette\Database) podporuje prefixy/suffixy.

Editoval Peppy (9. 7. 2011 18:08)

uestla
Backer | 799
+
0
-

Důležité je pochopit princip a myšlenku, nikoli Ctrl + C kombinované s Ctrl + V.

EDIT:

Omyl!

  1. Nespojuj si automaticky NotORM s Nette\Database
  2. prefixy fungují u Nette\Database stejně jako u dibi (důkaz)

Editoval uestla (9. 7. 2011 18:07)

Peppy
Člen | 137
+
0
-

Oukej. Nie? Tak teda nie :). Nikdy nerobím Ctrl + C a Ctrl + V. Je to proti mojej zásade.
EDIT:
A kam umiestniť tú továrničku? Tam, ako bol ten default-ný model?

Editoval Peppy (9. 7. 2011 18:19)

uestla
Backer | 799
+
0
-

To, co jsem poslal a v dnešním dusnu vypotil, je kompletní definice služby database, čili starou můžeš buď smazat, nebo raději jen zakomentovat (pokud neverzuješ…).

Peppy
Člen | 137
+
0
-

neverzujem. Ale kde dať tú factory? Ako globálny model najskôr, že?

uestla
Backer | 799
+
0
-

Kupríkladu hej (zde musím upozornit na mírnou chybu v terminologii – factory je přímo ta metoda, která službu vytváří, kdežto ty máš na své mysli onu třídu).

Peppy
Člen | 137
+
0
-

Jáj. A je nutnosť predať aj DI container (ako prvý argument), nevidím, žeby si s ním manipuloval…

Editoval Peppy (9. 7. 2011 18:52)

uestla
Backer | 799
+
0
-

Ten se továrničkám předává jako první automaticky, nevadí, že ho v samotném těle továrničky nepoužiješ.

Peppy
Člen | 137
+
0
-

A navyše v config.neon je:

		model:
			class: Model
			arguments: ["@database"]

class je Model, mám však iba BaseModel triedu. Príde mi to magické, odkiaľ Nette a ako zistí, že sa jedná práve o túto triedu…

uestla
Backer | 799
+
0
-

model je service, tj. stejná entita jako database. Tím bych se nevzrušoval vlka nic.

Chápu, že zrovna absence tohoto tématu v dokumentaci bolí mé prsty nejvíc, věřím ale, že se to co nevidět napraví.

Editoval uestla (9. 7. 2011 18:56)

Peppy
Člen | 137
+
0
-

Chcem to dať všetko dokopy (do modelu), aby som nemal milión tried. Proste BaseModel, kde budú všetky služby zaregistrované (v tom Base Modeli) ich továrničky. Aby to proste malo aj nejakú viac logickú myšlienku…

uestla
Backer | 799
+
0
-

Go ahead.

Peppy
Člen | 137
+
0
-

Tým myslím, že keď je všetko v jednom BaseModeli (všetky továrničky), nemusím ťahať nové súbory a triedy. Ide o to, ich správne nakonfigurovať v neone a to neviem…

uestla
Backer | 799
+
0
-

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

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

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?

  1. koukni, jak k chybě došlo, klidně použij překladač na chybové hlášky, neboj se toho
  2. zkoušej si dumpovat načtený konfig (dump($container->params); die(); v bootstrapu)
Peppy
Člen | 137
+
0
-

Robí to problémy u:

factory: [BaseModel, createServiceDatabase]
arguments: ['%database%'] # <--
uestla
Backer | 799
+
0
-

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

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

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

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

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)