SimpleAuthenticator v Nette2

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

Nejsme si jistý, jestli to dělám správně, může mě někdo zkontrolovat včetně config.neon /připojení k sqlite přes dibi/. Sice to funguje, ale jestli je to správně?

neon

common:
	php: # PHP configuration
		date.timezone: Europe/Prague
		# session.save_path: "%tempDir%/sessions"
		zlib.output_compression: yes
		default_charset: "UTF-8"

	services:
		authenticator:
			class: SimpleAuthenticator

		robotLoader:
			run: true

	database:
		driver: sqlite3
		database: %appDir%/db/db.sqlite
		profiler: true
		lazy: true
		run: true
		result:
			detectTypes: true

bootstrap

...
// Load configuration from config.neon file
$configurator = new Configurator();
$configurator->loadConfig(__DIR__ . '/config.neon');

// Connection to database
$connection = $configurator->container->params->database;
dibi::connect($connection);

// Configure application
$application = $configurator->container->application;
$application->errorPresenter = 'Error';
$application->catchExceptions = FALSE;

$authenticator = new SimpleAuthenticator(array(
	'admin'	=> '****',
));

$user = $configurator->container->user;
$user->setAuthenticationHandler($authenticator);
...

Editoval 22 (26. 5. 2011 22:00)

Filip Procházka
Moderator | 4668
+
0
-

Zdá se mi to, nebo nastavuješ 2× authenticator? To je opravdu potřeba?

bojovyletoun
Člen | 667
+
0
-

IMHO máš tam „dvakrát“ definici authenticatoru (v neonu a v php)

1. buď použij v neonu toto:

services:
                authenticator:
                        class: SimpleAuthenticator
			arguments:
				admin: root

2. nebo to v phpčku. A ještě bych to trochu přiupravil. Tímto způsobem při(e)dáváš authenticator do kontextu usera. Čistší a méně pracné se mi jeví toto: $config->cont['authenticator']=$authenticator; Resp. nepředávat $authenticator, ale schovat tvorbu authenticatoru do lmbda funkce, ať je to lazy.

22
Člen | 1478
+
0
-

přesněji řečeno, nezdá se mi:

neon:

services:
        authenticator:
                class: SimpleAuthenticator

to by tam asi nemuselo vubec byt anebo da se simple autheticator nejak nastavit komplet v neonu?

a pak:

$connection = $configurator->container->params->database;

nedá se k nastavení databáze dostat nějak jinak?
A jakou roli teď hraje Environment? Jsem z toho nějaký zmatený..

Edit: to řešení v configu se mi pozdává víc

Editoval 22 (26. 5. 2011 21:51)

22
Člen | 1478
+
0
-

@bojovyletoun: ten bod 2) můžeš to převést na kód, Nějak jsem to zatím nepobral.

bojovyletoun
Člen | 667
+
0
-
  • Environment hraje stejnou roli jako dřív. (jen si uprav kód dle toho ) Ale ty přece chceš používat DI? Tak žádné Environment nebudeme používat.
  • k přístupu. Vtip je v tom, že k db takhle, jak si psal „uvnitř“ aplikace nebudeš přistupovat (ani přes Environment – viz předchozí věta). v presenteru to bude takhle $this->context->params->database. Ale nevím, k čemu ti budou parametry připojení, asi jsi myslel služby modelu rovnou…
  • Ano Authenticator se dá nastavit v neonu jak jsem ukázal. Pro pochopení viz komentář v kódu zde
    • pomocí php:
//možnost 1(// hotový objekt )
$authenticator = new SimpleAuthenticator(array('admin' => '****',));
$configurator->container['authenticator']=$authenticator;

//možnost 2 (možnost 2 // pomocí lambda funkce.- objekt se vytvoří, pokud bude potřeba)
$configurator->container['authenticator']=function($context){
	return new Authenticator(array('admin'));
}   //proměnná $context je aktuální kontejner, klidně ji ignoruj

No, snad už trochu rouzumím DI.

Editoval bojovyletoun (26. 5. 2011 22:06)

22
Člen | 1478
+
0
-

ok, s DI už to chápu, Environment si mažu z hlavy :-) za ukázku nastaveni v neonu díky, ale ještě jak to myslíš s tou DB? ja přece vytvořím lazy spojení v bootstrapu a už se o to nikde v modelech nestarám a do dibi::connect() nějak dostat to pole, za starých časů to bylo:

dibi::connect(Environment::getConfig('database');

Editoval 22 (26. 5. 2011 22:09)

Tharos
Člen | 1030
+
0
-

Lazy připojení dibi můžeš provést například v $application->onStartup:

// Setup router
$application->onStartup[] = function() use ($application, $configurator) {

	dibi::connect($configurator->getContainer()->params['database']);

	// zde pokračuje definice rout
};

Tento kód předpokládá, že se někde „nad tím“ provede vytvoření $configurator:

// Load configuration from config.neon file
$configurator = new Nette\Configurator;
$configurator->loadConfig(__DIR__ . '/config.neon');

Přesně takto je to momentálně v sandboxu.

Editoval Tharos (26. 5. 2011 22:16)

22
Člen | 1478
+
0
-

hmhm, díky pánové! Měl jsem za to, že když mám v config.neon nastaveno lazy: true, tak to nemusím dávat do callbacku onStartup[]?

Tharos
Člen | 1030
+
0
-

Samozřejmě nemusíš, v případě lazy připojení je to opravdu jedno a to i z hlediska odchytávání případně vyhozených výjimek (vyhodí se v tom případě totiž až někde v modelové třídě mnohem později). V případě non-lazy připojení by to připojení ale určitě bylo vhodné umístit až za definici errorPresenteru (anebo odchytávat ručně).

Editoval Tharos (26. 5. 2011 22:37)

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Aby bylo dibi s DI (tedy vyhnutí se používání „statického registru dibi“), tak myslím by to mělo být košer takto:

$container = $configurator->getContainer();

$container->addService('dibi', function ($container) {
	return dibi::connect($container->params['database']);
});

Protože dibi je jen zkratka pro přístup k DibiConnection, které connect vrací.

bojovyletoun
Člen | 667
+
0
-

správná definice Authenticatoru (chyběly namespace předchozí zápis tvoříl new Authenticator('root',123) místo new Authenticator(array('admin'=>'root','eva'=>123)) – bylo nutné "vnořit pole

		authenticator:
			class:	Nette\Security\SimpleAuthenticator
			arguments:
				- # první a jedinný argument
					admin:	root # je pole
					eva:	123

vojtech.dobes mě předběhl – napsal defakto to samé, jen v php (což považuji za srozumitelnější oproti neonu

Databázi bych pořešil takto (pak by bylo spojení dostupné v presenteru pod $this->context->connection, za předpokladu, že pracuji rovnou s databází v presenteru, ale to je jiná věc)

		connection: # v sekci services
			class:	DibiConnection # pozn: dibi::connect() je totéž jako new DibiConnection
			arguments1:
				- %database% # zde je háček - v neonu se jde odkázat pouze na skalární typ
			arguments: #proto musíme nastavení vypsat sem
				-
					driver: mysql
					password: root

Editoval bojovyletoun (26. 5. 2011 23:22)

Tharos
Člen | 1030
+
0
-

@bojovyletoun: K čemu přesně slouží ty arguments1 a arguments? Já osobně registruji Dibi jako službičku v neonu takto a funguje to dobře:

common:
	services:
		dibi:
			class: DibiConnection
			option:
				driver: mysql
				charset: utf8
				lazy: true
				result:
					detectTypes: true

production < common:
	# zde je vynecháno doupřesnění option pro produkční server

development < common:
	services:
		dibi:
			option:
				host: localhost
				username: root
				password: xxxxx
				database: xxxxx

Přijde mi to jako nejjednodušší řešení. V presenteru se pak k DibiConnection přistupuje samozřejmě takto: $this->getContext()->dibi.

bojovyletoun
Člen | 667
+
0
-

arguments je synonymum pro option. arguments1 mělo demonstrovat, že se do argumentů konstruktoru mělo dosadit sekce database z configu (popsáno tam, vyhodí to exception „Parameter ‚database‘ is not scalar.“)

22
Člen | 1478
+
0
-

ještě malý problém v modelu s tímto:

dibi:
	class: DibiConnection
	option:
		driver: sqlite3
		database: %appDir%/db/sovereign.sqlite
		lazy: true
		profiler: true
		result:
			detectTypes: TRUE
			formatDateTime: TRUE
		run: true

profiler běží, ale když zavolám dibi z modelu, tak vyskočí Exception Dibi is not connected, takže jak to má být správně?
dřív stačilo v bootstrapu se připojit přes dibi::connect a dibi bylo dostupné i v modelu, což by mělo být stejné jako run: true

Tak co zase nevím?

Editoval 22 (30. 5. 2011 20:58)

bojovyletoun
Člen | 667
+
0
-

Totéž co zde, musíš parametry odsadit a vložit před ně prázndou pomlčku jako v odkazu. A nebo obalit parametry {{ nebo [[. Vize ne-on.org

22
Člen | 1478
+
0
-
dibi:
	class: DibiConnection
	arguments:
		-
			driver: sqlite3
			database: %appDir%/db/sovereign.sqlite
			lazy: true
			profiler: true
			result:
				detectTypes: TRUE
				formatDateTime: TRUE
	run: true

..fajn, ale model pořád hlásí: DibiException: Dibi is not connected to database :-(
Z toho, že v debugBaru je aktivní profiler, usuzuju, že connection je ale aktivní nebo inicializce nějak částečně proběhla…

Editoval 22 (30. 5. 2011 21:30)

Jur4
Člen | 51
+
0
-

Myslím, že problém je v tom, že takhle vytváříš službu jako instanci DibiConnection a v modelu používáš statické dibi a problém je v tom, že pokud to neprošlo přes dibi::connect tak dibi nemá o tom, že je někde vytvořena instance DibiConnection vuběc ponětí.

Editoval Jur4 (30. 5. 2011 21:44)

bojovyletoun
Člen | 667
+
0
-

no vidíš, mě hned napadlo, že staticky to už nevoláš a používáš DI. Takže buď používej DI ($this->context->dibi->fetch() a nebo si do configu nahraď class: DibiConnection za factory: dibi::connect ( ale DI budeš moci používat taky)

Editoval bojovyletoun (30. 5. 2011 22:11)

22
Člen | 1478
+
0
-

no, pořád nerozumím tomu, jak se dostanu jednoduše v modelu k ke spuštěné instanci DibiConnection v neonu v ramci DI?

Editoval 22 (30. 5. 2011 23:05)

bojovyletoun
Člen | 667
+
0
-

ve zkratce (pozpátku): (už se mi to nechce dopodrobna popisovat)))

  • $this->context->dibi->fetch()
  • PresenterFactory::createPresenter : $presenter->setContext($context) (původní context)
  • Application::getPresenterFactory->createPresenter
  • getPresenterfactory: application->getcontext->presenterfactory : Container::getservice (presenterFactory) (*)
  • Application->run
  • $configurator->application (viz *)
  • configurator->createservicepresenterfactory bere původní context
  • configurator::createserviceapplication
  • new Configurator;
22
Člen | 1478
+
0
-

jsem se inspiroval v examples a nakonec jsem to udělal takoto:

dibi:
	class: DibiConnection
	option:
		driver: sqlite3
		database: %appDir%/db/sovereign.sqlite
		lazy: true
		profiler: true
		result:
			detectTypes: TRUE
			formatDateTime: TRUE

testimonial:
	class: Models\TestimonialModel
	arguments: ["@dibi"]
class TestimonialModel extends BaseModel
{
	protected $conn;

	public function __construct($conn)
	{
		$this->conn = $conn;
	}

	public function getColumns()
	{
		return $this->conn->getDatabaseInfo()->getTable($this->table)->getColumnNames();
	}
}
srigi
Nette Blogger | 558
+
0
-

Velmi sa mi nepaci myslienka, ze pre kazdy Model budes vyrabat sluzbicku a konfigurovat ju v Neone. Osobne by som siel cestou nejakeho ModelLoadera ;)

Editoval srigi (31. 5. 2011 6:05)

22
Člen | 1478
+
0
-

myslíš jako?:

public $testimonialModel;

public function getTestimonial()
{
	if(!$this->testimonialModel) $this->testimonialModel = new TestimonialModel($this->context->dibi);
	return $this->testimonialModel;
}
...

Debugger::dump($this->testimonial);

proč to nedělat jako službu?

srigi
Nette Blogger | 558
+
0
-

@22: neviem ako presne riesis Modely v aplikacii, ale podla mna musi byt otravne pre kazdy Model pridavat sluzbicku so Neonu a pod. Takze ten loader myslim nieco take ako mam vo svojej kucharke:

private $connection = null;
private $models = array();

public function __construct($connection)
{
    $this->connection = $connection;
}

public function getModel($model)
{
    if (!isset($this->models[$model])) {
        $class = 'Model\\' . ucfirst($model);
        $this->models[$model] = new $class($this->connection);
    }

    return $this->models[$model];
}
22
Člen | 1478
+
0
-

jj, díky za inspiraci Srigi.

bojovyletoun
Člen | 667
+
0
-

Takhle se mi to líbí, jen bych to upravil tak, aby se v případě neexistence Model\EntityName vytvořil Model\BaseModel. A samozřejmě konstruktor upravit takto function __construct($connection,$EntityName)

22
Člen | 1478
+
0
-

ještě z5 k SA. Poslední Nette už umí expandovat sekci do objektu ArrayHash, ale SimpleAuthenticator očekáva v konstruktoru array, dá se config donutit, aby vyplivl čistý pole? Nebo upravit upravit SimpleAuthenticatoru na ArrayHash?:

common:
	services:
		authenticator:
			class: Nette\Security\SimpleAuthenticator
			arguments: ['%users%']

	users:
		admin: admin

jediný zápis, co mi vrací pole

			arguments:
				-
					admin: admin

což vypadá minimálně divně :-)

Editoval 22 (30. 6. 2011 5:27)

Patrik Votoček
Člen | 2221
+
0
-

Nedá ale můžeš řešit továrničkou. Nebo upravit upravit SimpleAuthenticatoru na ArrayHash? To bylo imho asi lepší (ale né na ArrayHash ale na Traversable).

22
Člen | 1478
+
0
-

no na ArrayHash jsem to přehodil, Traversable? To myslíš jak prosím? Nemělo by se to nějak vyřešit v rámci nějakýho pool requestu? To asi neni idealní šahat do tříd frameworku…

Filip Procházka
Moderator | 4668
+
0
-

Tohle je vskutku problém…

	test:
		test: [['one', 'two'], 'three', {lala: 'tada'}]
Nette\ArrayHash(1) {
   test => Nette\ArrayHash(3) {
      0 => Nette\ArrayHash(2) {
         0 => "one" (3)
         1 => "two" (3)
      }
      1 => "three" (5)
      2 => Nette\ArrayHash(1) {
         lala => "tada" (4)
      }
   }
}

Do teď jsem naivně doufal, že by to třeba mohlo tvořit pole, když to bude mít číselné klíče od nuly…

Patrik Votoček
Člen | 2221
+
0
-

22 napsal(a):

no na ArrayHash jsem to přehodil, Traversable?

http://php.net/traversable

Nemělo by se to nějak vyřešit v rámci nějakýho pool requestu?

No bazénem se to moc nepořeší… :-) Ale pull requestem bych to řešil… :-)

22
Člen | 1478
+
0
-

nevím, na co jsem myslel zrovna :-)

David Grudl
Nette Core | 8218
+
0
-

Configurator už negeneruje Nette\ArrayHash ale čisté pole.