Nedaří se přejít z nette 2.0b na nette 2.0 stable (2.0.13)
- mr.mac
- Člen | 87
Bohužel jsem nenašel jasný popis přechodu (či změn) z 2.0b na
2.0 stable nezbývá mi než se zeptat. Nedaří se mi převést stávající
(poměrně rozsáhlou) aplikaci z dřívější struktury config.neon a
bootstrap.php na nový (viz aktuální sandbox). Budu rád, když mi s tím
někdo pomůže.
Nejprve naznačím dosavadní podobu souborů config a bootstrap a pak co jsem
„zplodil“.
Stávající config.neon:
common:
php:
date.timezone: Europe/Prague
#nasledujici parametry nemzat - jen nastavit todos: true/false
myvar:
todos: true
#název a adresa firmy uživatele
company:
name: NameOfCompany
street: Street 123
city: Town
zip: 123 45
country: Czech Republic
services:
robotLoader:
run: true
model:
class: Model
arguments: [@database]
database:
class: DibiConnection
arguments: [%database%]
authenticator:
create: [@model, createAuthenticatorService]
authorizatorFactory:
class: AuthorizatorFactory
authorizator:
create: [@authorizatorFactory, create]
session:
arguments: [ [ expiration: "+ 2 days" ] ]
production < common:
development < common:
Nyní config.local.neon:
common:
database:
driver: sqlsrv
host: SQLSERVER
username: admin
password: password
database: DB
charset: utf-8
profiler: TRUE
production < common:
development < common:
database:
host: .\SQLEXPRESS
username: user
password: pass
A nyní bootstrap.php (neděste se prosím – je to můj první projekt více než 2 roky starý):
use Nette\Diagnostics\Debugger,
Nette\Application\Routers\Route,
Nette\Application\Routers\RouteList,
Nette\Application\Routers\SimpleRouter;
// Load Nette Framework
require $params['libsDir'] .'/Nette/loader.php';
// Load Dibi library
require $params['libsDir'] .'/Dibi/Dibi.php';
// Enable Nette Debugger for error visualisation & logging
Debugger::$strictMode = TRUE;
Debugger::$logDirectory = $params['logDir'] ;
Debugger::enable(Debugger::DEVELOPMENT);
// Load configuration from config.neon file
$configurator = new Nette\Configurator;
$configurator->container->params += $params;
$configurator->container->params['tempDir'] = __DIR__ . '/../temp';
$container = $configurator->loadConfig(__DIR__ . '/config.neon');
$container = $configurator->loadConfig(__DIR__ . '/config.local.neon');
// Setup router using mod_rewrite detection
if (function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules())) {
$container->router = new RouteList;
$container->router[] = new Route('index.php', 'Homepage:default', Route::ONE_WAY);
$container->router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
} else {
$container->router = new SimpleRouter('Homepage:default');
}
// create DB connection
dibi::connect($container->params['database']);
$application = $container->application;
$application->errorPresenter = 'Error';
//DateInput register
Vodacek\Forms\Controls\DateInput::register();
// Run the application!
$application->run();
Aktuálně jsem se pokusil zjednodušit config.neon takto (local jsem zatím vypustil):
common:
parameters:
# Sem napsat vlastní konstanty - nevím jak?
php:
date.timezone: Europe/Prague
nette:
application:
errorPresenter: Error
session:
expiration: 14 days
model:
class: Model
arguments: [@database]
database:
class: DibiConnection
host: .\SQLEXPRESS
username: user
password: pass
charset: utf-8
profiler: TRUE
# pokus o nové services - nefunkční
services:
routerFactory: RouterFactory
router: @routerFactory::createRouter
authenticator: Authenticator
authorizator: AuthorizatorFactory
create: @authorizator::create
database:
class: dibi
create: dibi::connect
arguments: [@database]
model:
class: Model
# arguments: [@database]
# původní services - nefunkční
# authenticator:
# create: [@model, createAuthenticatorService]
#
# authorizatorFactory:
# class: AuthorizatorFactory
#
# authorizator:
# create: [@authorizatorFactory, create]
factories:
production < common:
development < common:
A nakonec nový bootstrap.php:
// Load Nette Framework or autoloader generated by Composer
require __DIR__ . '/../../lib/autoload.php';
$configurator = new Nette\Config\Configurator;
// Enable Nette Debugger for error visualisation & logging
$configurator->enableDebugger(__DIR__ . '/../log');
// Specify folder for cache
$configurator->setTempDirectory(__DIR__ . '/../temp');
// Enable RobotLoader - this will load all classes automatically
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->addDirectory(__DIR__ . '/../../lib')
->register();
// Create Dependency Injection container from config.neon file
$configurator->addConfig(__DIR__ . '/config/config.neon');
$container = $configurator->createContainer();
return $container;
Problém je aktuálně ten, že se mi nedaří spustit aplikaci, ta končí
následující chybou:
Service of type Nette\Security\IAuthorizator not found
přičemž v knihovně samozřejmě interface IAuthorizator uložen je.
Editoval mr.mac (30. 11. 2013 21:07)
- enumag
- Člen | 2118
Tohle
services:
authorizator: AuthorizatorFactory
create: @authorizator::create
změň na
services:
authorizatorFactory: AuthorizatorFactory
authorizator: @authorizatorFactory::create
Tohle samozřejmě nevyřeší problém, jen máš ty služby divně pojmenované. Mohl bys ukázat AuthorizatorFactory?
Editoval enumag (30. 11. 2013 19:54)
- mr.mac
- Člen | 87
enumag napsal(a):
Tohle samozřejmě nevyřeší problém, jen máš ty služby divně pojmenované. Mohl bys ukázat AuthorizatorFactory?
Díky za snahu o pomoc, trochu se v tom inovovaném config.neon topím (je
někde popáno „co všechno“ tam může být definováno?).
K tvému dotazu: Mám udělaný vlastní authorizator v DB asi tam chyba
nebude, to mi ve 2.0b funguje dobře, zde je část kódu:
use Nette\Security\Permission;
class AuthorizatorFactory extends Nette\Object
{
private $permission;
public function create(){
$permission = new Permission;
// roles
$prava = new Prava;
$roles = $prava->getRole();
$permission = $this->setRolesDB($roles);
$this->permission = $permission;
// resources sets
$zdroje = $prava->getResources();
$this->setResourcesDB($zdroje);
// privileges sets
$this->setPrivilegesDB();
$permission->allow('Admin', Permission::ALL, Permission::ALL);
$this->permission = $permission;
return $permission;
}
... dále už jen definice výše použitých metod
}
Editoval mr.mac (30. 11. 2013 20:31)
- enumag
- Člen | 2118
Zkus tam přidat anotaci:
use Nette\Security\Permission;
class AuthorizatorFactory extends Nette\Object
{
//...
/**
* @return \Nette\Security\IAuthorizator
*/
public function create(){
//...
}
}
Ta anotace musí být fully-qualified. V Nette 2.1 final to možná půjde i přes use statementy, na GitHubu se o tom právě vede diskuse.
Editoval enumag (30. 11. 2013 20:55)
- mr.mac
- Člen | 87
enumag napsal(a):
Zkus tam přidat anotaci:
Díky moc, pomohlo to, teď mám asi nesprávně načtené parametry
z neonu, neboť mi laděnka hlásí Dibi is not connected to
database, což se ani nedivím, (používám Dibi), protože určitě
mám špatně v neonu službu k vytvoření connection k databázi. Jak by to
tam mělo být správně?
Konstruktor v modelu mám totiž tento:
use Nette\DI\Container;
class Model extends DibiRow
{
/** @var Dibi\Connection */
public $CONN;
public function __construct($arr = array())
{
parent::__construct($arr);
$this->CONN = dibi::getConnection();
}
...
Editoval mr.mac (30. 11. 2013 21:01)
- enumag
- Člen | 2118
Správně bys měl asi použít DibiExtension. Instaluje se to v bootstrapu takhle: https://doc.nette.org/…n/extensions. V Nette 2.1 to půjde instalovat přes neon.
S dibi konkrétně ti ale neporadím protože ji nepoužívám. Každopádně to statické getConnection zřejmě bude vadit.
Editoval enumag (30. 11. 2013 21:07)
- mr.mac
- Člen | 87
No s tím moc zkušenosti nemám, dříve jsem měl v bootstrapu na tvrďáka toto:
// create DB connection
dibi::connect($container->params['database']);
Jenomže teď mi to hlásí chybu, Undefined index:
database, když si dumpnu ten $container
, tak tam nějak
nevidím pole database
načtený z neonu, nevíš jak se na něj
v bootstrapu odkázat, to by mi zatím stačilo a nechal bych to „po
staru“, ale (snad) už s novou verzí nette a pak se budu postupně snažit
to doladit. V každém případě díky.
Dump $container
(nevidím ty načtené objekty z neonu):
SystemContainer(8) ▼ {
classes => array(38) ►
meta => array(0)
parameters => array(8) ►
params => array(8) ▼ {
appDir => "C:\\xampp\htdocs\ems2\app" (24)
wwwDir => "C:/xampp/htdocs/ems2/www" (24)
debugMode => TRUE
productionMode => FALSE
environment => "development" (11)
consoleMode => FALSE
container => array(2) ▼ {
class => "SystemContainer" (15)
parent => "Nette\DI\Container" (18)
}
tempDir => "C:\\xampp\htdocs\ems2\app/../temp" (32)
}
...
Editoval mr.mac (30. 11. 2013 21:44)
- mr.mac
- Člen | 87
To nefunguje, chyba Circular reference detected for services:
database. Jen mi jde o to, že v systémovém kontejneru nevidím ty
parametry, které jsou uloženy v config.neon a měly by být
načteny/vytvořeny v kontejneru metodou
$container = $configurator->createContainer()
. Tedy alespoň si
to myslím.
- mr.mac
- Člen | 87
enumag napsal(a):
Díky, zase jsem o kousek dál. Opravil jsem to dle tvé rady, ještě jsem
to musel pozměnit a nakonec jsem se dopracoval k „relativně funkčnímu“
stavu. Database jako služba zatím nic.
V bootsatrapu „zatím bohužel“ mám připojení natvrdo:
dibi::connect($container->params['database']);
A v config.neon toto – a chodí to:
services:
routerFactory: RouterFactory
router: @routerFactory::createRouter
authenticator: @model::createAuthenticator
authorizatorFactory: AuthorizatorFactory
authorizator: @authorizatorFactory::create
model:
class: Model
arguments: [@database]
database:
class: DibiConnection
arguments: [%database%]
Jenom pořád nevím kam uložit v config.neonu svoje proměnné v sekci constants to řve Constants may only evaluate to scalar values, což chápu, je někde požadovaná nová struktura config.neon popsaná?
Editoval mr.mac (1. 12. 2013 12:50)
- mr.mac
- Člen | 87
enumag napsal(a):
Do parameters přece.Btw. tohle nefunguje? Takhle se ti to spojení dost možná vytváří 2×.
Nevím proč, ale v sekci parameters mi to řvalo, potom jsem si config.neon
trochu „pročistil“ a je to ok, díky, už fakt blbnu.
To s tím dvojím připojením k DB mě taky napadlo, ale zatím ten tvůj
postup opravdu stále hlásí, že spojení není vytvořeno.
Mám tady
však ještě ještě jeden dotaz, zatím bez odezvy – myslíš, že by to
mohlo být tím dvojím připojením (vytváří se duplicity
v záznamech)?
Editoval mr.mac (1. 12. 2013 13:30)
- mr.mac
- Člen | 87
Tak jsem se pokusil zprovoznit svou aplikaci přímo pod Nette 2.1 RC4 a
nedaří se mi autentikace, laděnka hlásí
Authenticator has not been set.
po odeslání přihlašovacího
formuláře v SignPresenteru (na předposledním řádku při volání metody
login):
public function signInFormSubmitted($form){
try {
$values = $form->values;
$this->getUser()->login($values->username, $values->password);
$this->application->restoreRequest($this->backlink);
...
V config.neon mám to co uvádím výše:
...
services:
routerFactory: RouterFactory
router: @routerFactory::createRouter
authenticator: @model::createAuthenticator
authorizatorFactory: AuthorizatorFactory
authorizator: @authorizatorFactory::create
...
V modelu mám:
public function createAuthenticator() {
return new Authenticator($this->CONN->dataSource('SELECT u.*, r.nazev [nrole]
FROM users u LEFT JOIN role r ON u.role=r.id'));
}
Může mi prosím někdo pomoci? Díky předem!
- Šaman
- Člen | 2666
Předpokládám, že ta tvoje třída Authenticator
implementuje
rozhraní IAuthenticator? (V novém Nette jsou ty názvy služeb zbytečné,
pokud si je sám netaháš podle jména. Důležité je jejich rozhraní.)
Add: Ještě si do configu do sekce nette
můžeš přidat
ladicí panel s výpisem celého kontejneru, aspoň budeš vědět, jestli se
ti ta služba vytvořila, nebo ne:
nette:
container:
debugger: true
Editoval Šaman (22. 12. 2013 19:38)
- mr.mac
- Člen | 87
Díky za reakci a tip. Authenticator mám implementovaný „snad“ standardně:
use Nette\Object,
Nette\Diagnostics\Debugger,
Nette\Security as NS,
Nette\Security\Identity,
Nette\Security\AuthenticationException;
/**
* Users authenticator.
*/
class Authenticator extends Object implements NS\IAuthenticator
{
private $users;
public function __construct($users = array())
{
$this->users = $users;
}
...
Bohužel v systémovém kontejneru mám u položky
authenticator: Autowired: no
, např. AuthorizatorFactory mi běží
(viz můj config.neon). Bohužel autenticator stále nic.
EDIT: Tak authenticator mi už běží, změnil jsem v config.neon toto:
services:
authenticator: Authenticator
Bohužel na posledním řádku následujícího kódu mi laděnka hlásí
Call to a member function where() on a non-object
,
přitom pokud jsem se z aplikace neodhlásil, tak mi připojení k DB pomocí
Dibi fungovalo dobře.
public function authenticate(array $credentials){
list($username, $password) = $credentials;
$row = $this->users->where('username = %s', $username)->fetch();
Pole users
je totiž prázdné, asi se neprovedla v modelu
createAuthenticator (viz výpis configu výše). Nějak se v tom topím …
bohužel v quick startu toho moc nenačtu a asi ani jinde, změny jsou
rychlejší než návody :-(.
Už to funguje – viz níže.
Editoval mr.mac (23. 12. 2013 12:48)
- mr.mac
- Člen | 87
Tak nevím, jestli jsem neměl vyprázděnou cache, ale když jsem vrátil
v config.neonu službu asi jak měla být
authenticator: @model::createAuthenticator
tak v contejneru
vidím, že běží, pole users
existuje a je naplněno.
Avšak teď mi laděnka hlásí:
Nette\Application\UI\Presenter::getApplication() is deprecated; use
dependency injection instead. v SignPresenteru na řádku 43:
38: public function signInFormSubmitted($form)
39: {
40: try {
41: $values = $form->values;
42: $this->user->login($values->username, $values->password);
43: $this->application->restoreRequest($this->backlink);
44: $this->getPresenter()->getApplication()->restoreRequest($this->getPresenter()->backlink);
EDIT:
Potřebuji se dostat na původní stránku, kam zněl odkaz (musel jsem být
„odkloněn“ na přihlášení). V Nette 2.0b mi tyto 2 řádky (43, 44)
fungovaly bezchybně – něco se změnilo?
Editoval mr.mac (23. 12. 2013 12:48)