Implementace Nette do starého informačního systému
- stepos
- Člen | 36
Hezký den,
jsem nadšený z Nette a moc rád bych v něm programoval náš stávající
informační systém. Je to moloch – odhaduji kolem 100 000 řádků v php
programovaný víc než deset let. Ale dost špatně, částečně neobjektově,
žádné html šablony, samý require, žádný MVC model… Nechci ho
přeprogramovávat, ale pokračovat ve vývoji smysluplnějším způsobem.
Staré funkce nechat umřít, nové programovat v Nette.
Jaký je nejlepší způsob implementace Nette do staré aplikace s vlastní adresářovou strukturou? Tak, abych od teď mohl již programovat pořádně, ale současně používat starý systém, aniž by se uživatelé museli přihlašovat na některé funkce do nového portálu?
Díky za odpověď!
Štěpán
- Jan Suchánek
- Člen | 404
@stepos to budeš muset hodně oddělit, a nebo budeš muset používat jen časti nette, tzn zapomenout na Presentery i další fičury, nebo jak části Nette používáte na bastl to by mě taky zajímalo.
Spíš si myslím že k bastlu je takovej odpor že se píše vše znova.
Editoval jenicek (27. 4. 2015 20:16)
- David Kudera
- Člen | 455
Osobně s tím nemám žádnou zkušenost, ale co mě tak napadá:
Záleží to na tom, jestli používáš mod rewite nebo ne. Pokud ne, tak by to mohlo být celkem snadný, jinak nějak složitěji vyřešit bod 3.
- Kompletně celý systém přesunout někam do složky www v novém systému.
- Přenastavit server apache/nginx, aby koukal do složky www
- Tady nějak vymyslet, jak přesměrovat neexistující stránky v novým na ten starý. Někdo nějaký lehký nápad? :-) Jinak by jsi musel chodit třeba přes domena.cz/old/ nebo prostě přes složku, do které by jsi to nahrál
- Nachystat si přihlášení v nette (nemyslím formulář, viz bod 5)
- Ve starém systému requirnout bootstrap.php, který vrací container, z něj vytáhnout user a pracovat ve starým systému s nette userem
- Postupně vše přepsat do nette a starého se co nejdřív zbavit ;-)
No a teoreticky by to mohlo fungovat
- winner21
- Člen | 5
Asi nejlepší budeš mít implementovat si rozhraní IUserStorage https://api.nette.org/…Storage.html tak, aby ti fungovalo se starým systémem.
- Filip Procházka
- Moderator | 4668
Viděl jsem tuhle pěknej návod jak převést legacy applikaci pod Symfony. Udělal bych to velice podobně.
- Založil bych si novej projekt, udělal bych si jeden presenter, kterej bude předávat requesty na starou aplikaci a začal přepisovat.
- Napsal bych si router který bude zpracovávat url aby kopírovaly schéma adres starého systému, abych si mohl generovat adresy z Nette a přijímat je jako requesty a tunelovat přes ten „legacy“ presenter do starého systému
- Nový věci rovnou s novýma modelama pod Nette.
- Pokud to půjde, tak používat DI Container aspoň jako Service Locator ve staré aplikaci.
- Postupně přepisovat všechno do Nette a mazat starý kód.
- Profit
:)
- kejlicz
- Člen | 201
Pro Filip Procházka : Můžeš prosím upřesnit, jak by jsi řešil to " tunelovat přes ten „legacy“ presenter do starého systému".
O něco takového se pokouším, ale nějak mi není jasné, jak by jsi to z toho presenteru přesměrovával na starou URL, protože by to přesměrování opět zachytil htaccess z Nette a poslal by to do Nette. Asi mi něco uniká.
- Filip Procházka
- Moderator | 4668
@kejlicz nemáš přesměrovávat, máš tam například includnout scripty ze staré aplikaci, nebo zavolat nějaký starý controller, zkrátka to co by se volalo na té staré url.
- kejlicz
- Člen | 201
Filip Procházka napsal(a):
@kejlicz nemáš přesměrovávat, máš tam například includnout scripty ze staré aplikaci, nebo zavolat nějaký starý controller, zkrátka to co by se volalo na té staré url.
Zasekl jsem se na jedný věci. Stará aplikace používá toto
ve spuštěném scriptu je v globálním prostoru vytvořen objekt pro práci s db
$database = new Database();
soubor s třídou, která používá databázi
class Trida()
{
public function metoda()
{
global $database;
$database->dotazPole("SELECT ...");
.....
}
}
Když spustím přímo script, tak to funguje. Když ale chci script includovat v metodě presenteru, tak class Trida hodí chybu, že $database neni objekt. Pokud to dobře chápu, $database se při přímém spuštění vytvoří v globálním prostoru a pak je přes příkaz global dostupná. Když se spouští přes presenter, již se vytváří jinde a tudíž se k ní přes global nedostanu.
Jak tohle vyřešil bez zásahu do starých scriptů?
Díky za pomoc.
Editoval kejlicz (27. 5. 2015 13:31)
- kejlicz
- Člen | 201
To hodí syntax error, tak jsem to zkusil napsat jinak a to projde a funguje to.
global $database;
$database = new Database();
Sice by to znamenalo úpravu původních scriptů, ale pokud to nepůjde jinak, nedá se nic dělat.
Unlink napsal(a):
Ak pridáš global pred tú deklaráciu tak to nepôjde?
global $database = new Database();
Editoval kejlicz (27. 5. 2015 22:17)
- stepos
- Člen | 36
kejlicz napsal(a):
@FilipProcházka Aha, tak to zkusím. Dík.
Ahoj, můžeš mi prosím tedy poradit, jak jsi to udělal?
Prosím zkus to polopatě, s nette začínám a dost to bolí;)
Mám prostě adresářovou strukturu v nette a pak mám někde jinde
adresářovou strukturu původní rozsáhlé aplikace.
Jak a kam nakopírovat původní aplikaci? Do www/puvodni_aplikace?
Jak a kde includovat?
Jak v nové aplikaci tvořit odkazy na starou a naopak ve staré odkazy do
nové aplikaci?
Díky, a omlouvám se za možná blbý dotazy, jsem fakt zmaten;)
Š+
- kejlicz
- Člen | 201
Měl jsem starou aplikaci v root adresáři. Tam jsem nahrál do
podadresáře sandbox Nette. Pak jsem si v htaccess nasměroval požadavky na
scripty do podadresáře Nette. V Nette jsem si vytvořil routy, které
přesně popisovali staré URL adresy a ty nasměroval na LegacyPresenter. Tohle
asi nejde nějak obecně popsat. Záleží jakou máš strukturu aplikace a
URL.
Ukázka routy
$router[] = new Route('volna-mista/<okres>[/index.php?page=<page>]', array(
'presenter' => 'Legacy',
'action' => 'vm'
));
takže jsem požadavky např. na domena.cz/volna-mista/jicin/ poslal na tuhle action v LegacyPresenteru
public function actionVm($okres, $page = NULL)
{
include "../volna-mista/jicin/index.php";
die;
}
Odkazy jsem zatím nedělal, ale pokud budou dobře routy, budeš normálně v nette generovat URL klasicky a měly by odpovídat staré struktuře.
- stepos
- Člen | 36
Díky moc.
A jde to i opačně?
Mít adresářovou strukturu Nette, ve které psát novou aplikaci košér.
Do adresáře /vendor hodit celou původní složku se starým systémem
s requiry atd.
Tzn. /vendor/old/index.php
V RouterFactory doplnit řádek se starým systémem
public static function createRouter()
{
$router = new RouteList();
//stary systém
$router[] = new Route('old', 'Legacy:old');
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
Route::$defaultFlags = Route::SECURED;
return $router;
}
a presenter:
<?php
namespace App\Presenters;
use Nette,
App\Model;
/**
* Legacy presenter. - do starého systemu
*/
class LegacyPresenter extends BasePresenter
{
public function renderDefault()
{
// $this->template->anyVariable = 'any value';
}
public function actionOld()
{
include "../vendor/old/index.php";
die;
}
}
Problém, že to tak nefunguje.
Teda, když zadám odkaz localhost/newapp/old
Routing debugger praví, že byl použit správný router, nicméně se nic
nevykreslí, prázdná obrazovka (ani echo „ahoj“ nefunguje…).
Začínám, tak se omlouvám, ale tápu, tápu, tápu.
Děkuji
Editoval stepos (4. 6. 2015 13:21)
- stepos
- Člen | 36
Ahoj, tak jsem se po několika měsících konečně dopracoval
k implementaci Nette do starého rozsáhlého informačního systému. Zvolil
jsem nakonec adresářovou strukturu Nette, ve které píšu nové funkce, do
starého systému přistupuju přes router a presenter, který mi includuje
staré soubory /viz výše/.
Mám ten starý systém v adresářové struktuře Nette ve složce
www/old/index.php…
Právě počítám s tím, že uživatelé se budou přihlašovat přes formuláře tvořené v Nette. Pokud bude potřeba vstoupit do starého systému, rád bych mu předal informaci, že uživatel je přihlášený, aby se nemuselo zadávat znovu heslo do starého systému, ale současně, aby se dalo přihlašovat do starého po staru
Chtěl bych zkusit do starého systému načíst informace o přihlášení
z Nette, nevíte, kudy nejlépe?
Napadlo mě načíst si identitu $user, ale mám problémy se jmennými
prostory, ať chci cokoliv použít z Nette, píše mi to Class Nette\Object
nenalezena.
Pokud použiju namespace Nette, nefungují mi zase staré třídy, které to
nemají.
Existuje nějaký způsob, jak toto vyřešit? Abych nemusel ve všech souborech
starých tříd definovat namespace, protože teď žádný nemají.
Pak leda přistupovat k identitě přes sessions, ve starém systému se nějak dostat do sessions, kde je uložena identita – to by snad mohlo jít, protože je vnořený v nette, čili ve stejné doméně na stejném počítači ve stejném prohlížeči… Ty sessions by pak sloužily i k dalšímu předávání informací a signálů mezi systémy. Děkuji za případné postrčení.
- stepos
- Člen | 36
php 5.6.17, nette přes composer
rozhodl jsem se jít cestou přes to sessions, nette při autentizaci uloží do session informaci o tom, že už je ověřený, a starý systém si informaci načte a už hesla neřeší.
Problém mám trochu s DI, zase v tom plavu,a to jsem myslel, že to už chápu. Mám vlastní autenticator:
Authenticator.php
namespace Model;
use Nette\Security as NS;
class Authenticator extends \Model\BaseRepository implements NS\IAuthenticator
{
const
TABLE_NAME = 'i_users'...
...
/** @var Nette\Http\Session */
private $session;
/** @var Nette\Http\SessionSection */
private $sessionSection;
/**
* Performs an authentication.
* @return Nette\Security\Identity
* @throws Nette\Security\AuthenticationException
*/
public function authenticate(array $credentials)
{
list($username, $password) = $credentials;
$row = $this->database->table(self::TABLE_NAME)->where(self::COLUMN_NAME, $username)->fetch();
if (!$row) {
throw new NS\AuthenticationException('Jméno nebo heslo není zadáno správně.', self::IDENTITY_NOT_FOUND);
} elseif (!NS\Passwords::verify($password, $row[self::COLUMN_PASSWORD_HASH])) {
// \Tracy\Debugger::dump(NS\Passwords::hash($password));
throw new NS\AuthenticationException('Jméno nebo heslo není zadáno správně.', self::INVALID_CREDENTIAL);
} elseif (NS\Passwords::needsRehash($row[self::COLUMN_PASSWORD_HASH])) {
$row->update(array(
self::COLUMN_PASSWORD_HASH => Passwords::hash($password),
));
}
$roles_arr = $this->database->table(self::ROLES_NAMES_TABLE)->select(self::COLUMN_ROLE_NAME)->where(self::COLUMN_ROLE_ID,$this->database->table(self::USER_ROLES_TABLE)->select(self::COLUMN_ROLES_ROLE)->where(self::COLUMN_ROLES_USER, $row[self::COLUMN_ID]))->fetchPairs(NULL, self::COLUMN_ROLE_NAME);
// \Tracy\Debugger::dump($roles_arr);
$arr = $row->toArray();
unset($arr[self::COLUMN_PASSWORD_HASH]);
//nastavíme starému systému identitu
$this->authenticateOldSystem($username);
return new NS\Identity($row[self::COLUMN_ID], $roles_arr, $arr);
}
/**
*
* @param \Model\Nette\Http\Session $session
* získá přístup k sessions a uloží starému systému informaci o tom, že uživatel byl autentifikován v nette
*/
private function authenticateOldSystem($identity_name, \Nette\Http\Session $session)
{
$this->session = $session;
$this->sessionSection = $session->getSection(self::OLD_SYSTEM_SESSION_SECTION);
$this->session->{self::OLD_SYSTEM_SESSION_VARIABLE}=$identity_name;
}
BaseRepository.php
namespace Model;
use Nette;
abstract class BaseRepository extends Nette\Object {
/** @var Nette\Database\Context */
protected $database;
public function __construct(Nette\Database\Context $database) {
$this->database= $database;
}
}
Hází mi to chybu:
Argument 2 passed to Model\Authenticator::authenticateOldSystem() must be
an instance of Nette\Http\Session, none given, called in
/home/www/ikona/app/model/Authenticator.php on line 55 and defined
Teď jsem se zamotal. Dělá se to tak, že Authenticator.php bude mít svůj konstruktor, kde si získá závislost na \Nette\Http\Session. Nebude se to tlouct se zděděným konstruktorem s BaseRepository, kde se získává závislost na databázi? Někde jsem tu četl, že se to moc dělat nemá, protože ty konstruktory se tlučou, ale nevím, přečetl jsem toho hodně.:) Přijde mi nesystémové získávat závislost už v baseRepository a dědit ji. BaseRepository ji nepotřebuje…
Díky. Š+
- romiix.org
- Člen | 343
Nemá to nič s DI.
Voláš $this->authenticateOldSystem($username);
, pri čom
definíciu metódy máš
private function authenticateOldSystem($identity_name, \Nette\Http\Session $session)
Asi by si mal zmeniť kód na:
private function authenticateOldSystem($identity_name)
{
$this->sessionSection = $this->session->getSection(self::OLD_SYSTEM_SESSION_SECTION);
$this->sessionSection->{self::OLD_SYSTEM_SESSION_VARIABLE}=$identity_name;
}
Nejak detailne som to neskúmal.
- romiix.org
- Člen | 343
Cez konštruktor:
public function __construct(\Nette\Http\Session $session) {
$this->session = $session;
}
V konfiguračnom config.neon
stačí:
- Model\Authenticator
Následne to Autowiring zariadi.
Editoval romiix.org (3. 2. 2016 15:03)