Medick version 0.4.0 was released today.
For download you can use one of berlios mirrors.
This is a “still alive” release, it contains only a very small list of new features ( like rendering JSON ) and improvements.
Most important in medick-0.4.0 database settings are reverted to the original XML format and ActionController::before_filter was renamed to ActionController::before_filters (notice the plural form).
Also, I have added after_filters for ActionController.
For a complete list of changes see the CHANGELOG file.
Medick is a PHP 5 Web Framework (not a collection of PHP classes) released under a BSD style LICENSE.
Help wanted
I need some help with medick on building a nice logo for the project and with some suggestions on how to design / improve the layout of the framework web site.
Medick version 0.3.0pre2 was released today.
For download you can use one of berlios mirrors.
Since database configuration settings where moved from the xml file to a conf/database.ini this version is not compatible with older versions. Learn how to upgrade your medick applications to 0.3.0pre2 from this message posted on the internal development list.
For a complete list of changes see the CHANGELOG file.
Medick is a PHP 5 Web Framework (not a collection of PHP classes) released under a BSD style LICENSE.
Medick 0.3.0pre2 Released, written by aurelian in
medick,
|
No Comments
Eram dator de ieri cu rezultatele testului de performata la care a fost supus Medick.
Sincer sa fiu, ma asteptam la rezultatele obtinute. PHP-ul (mod_php) nu poate concura (prin natura sa) cu 10 instante de Mongrel sau cu Python (mod_python). Am vrut totusi sa vad ce diferente sunt si cum reactioneaza Medick comparativ (in special) cu Symfony.
Tunning
Pentru Apache Prefork am utilizat exact metoda de tunning descrisa in testul ce a servit ca inspiratie (si comparatie) pentru acest articol:
StartServers 5
MinSpareServers 5
MaxSpareServers 10
ServerLimit 150
MaxClients 150
MaxRequestsPerChild 10000
Pentru ca am folosit InnoDB ca storage engine pentru MySQL, am adaugat (activat) in my.cnf urmatoarele setari:
innodb_buffer_pool_size = 64M
innodb_additional_mem_pool_size = 16M
Test 1: 30 minute, 50 Utilizatori Concurenti, APC Activat
Transactions: 91179 hits
Availability: 99.87 %
Elapsed time: 1801,60 secs
Data transferred: 86.96 MB
Response time: 0.43 secs
Transaction rate: 50.61 trans/sec
Throughput: 0.05 MB/sec
Concurrency: 21.62
Successful transactions: 91175
Failed transactions: 116
Longest transaction: 30.01
Shortest transaction: 0.01
Transactions (91179 hits), inseamna ca am primit numarul asta de acesari in Elapsed Time (1801.60 sec). Serverul a fost disponibil in proportie de Availability (99.87 %), timp in care am transferat Data transferred (86.96) MB. Transaction rate (50.61) reprezinta numarul de tranzactii pe secunda (mai mare mai bine). Cand serverul timite un cod de raspuns 200 inseamna ca tranzactiile au fost efectuate cu succes, Successful transactions (91175), in cazul unui raspuns diferit de 200, tranzactia este esuata, Failed transactions (116).
Se poate observa ca, de 4 ori, serverul a fost de negasit.
Test 2: 3 minute, 50 Utilizatori Concurenti, APC Dezactivat
Transactions: 2561 hits
Availability: 99.38 %
Elapsed time: 181,32 secs
Data transferred: 2.38 MB
Response time: 2.64 secs
Transaction rate: 14.12 trans/sec
Throughput: 0.01 MB/sec
Concurrency: 37.24
Successful transactions: 2559
Failed transactions: 16
Longest transaction: 30.61
Shortest transaction: 0.07
Test 3: 3 minute, 50 Utilizatori Concurenti, APC Activat
Transactions: 10279 hits
Availability: 100.00 %
Elapsed time: 185.94 secs
Data transferred: 9.52 MB
Response time: 0.40 secs
Transaction rate: 55.28 trans/sec
Throughput: 0.05 MB/sec
Concurrency: 21.91
Successful transactions: 10279
Failed transactions: 0
Longest transaction: 6.64
Shortest transaction: 0.01
Test 4: 3 minute, 150 Utilizatori Concurenti, APC Activat
Transactions: 14501 hits
Availability: 99.18 %
Elapsed time: 189.25 secs
Data transferred: 36.94 MB
Response time: 0.62 secs
Transaction rate: 76.62 trans/sec
Throughput: 0.20 MB/sec
Concurrency: 47.82
Successful transactions: 1881
Failed transactions: 120
Longest transaction: 25.28
Shortest transaction: 0.00
Concluzii
Se poate observa ca Medick a raspuns la fel de bine ca Symfony pe o platforma hardware inferioara, numarul mai mare de tranzactii efectuate vine probabil din dimesiumea (mai mica) paginii servite.
APC imbunatateste performanta de 5 ori, lucru observat prin comparatia directa a rezultatelor din testele 2 si 3.
Din pacate aceasta extensie nu va fi prezenta pe serverele unde gazduim paginile web scrise in PHP. Iar zvonul ca extensia APC va fi prezenta si activata in mod implicit in PHP 6, este, well, doar un zvon, si nu cred ca se va intampla acest lucru. Plus, la ritmul de dezvoltare, acoperire si utilizare PHP 6 va fi disponibil cam in 3-4 ani.
Testul 4 m-a pus pe ganduri, serverul MySQL a cedat foarte repede. Rezultatele obtinute de Rails (Ruby) sau Django (Python) ma fac sa cred ca problema sta in clientul mysql din PHP.
Asa ca, am repetat acest test, insa recunosc ca am trisat modificand o linie de cod din ActiveRecord adaugand flagul ce marcheaza conexiunea la baza de date ca fiind persistenta (Creole::PERSISTENT).
Transactions: 11410 hits
Availability: 99.78 %
Elapsed time: 214.80 secs
Data transferred: 10.88 MB
Response time: 2.14 secs
Transaction rate: 53.12 trans/sec
Throughput: 0.05 MB/sec
Concurrency: 113.65
Successful transactions: 11408
Failed transactions: 25
Longest transaction: 24.69
Shortest transaction: 0.03
Ce am invatat?
APC aduce un plus de performanta.
Medick are nevoie de setarea diferitilor parametri de conectare la baza de date in fisierul de configurare.
Pe o platforma hardware asemanatoare Medick ar fi mult mai rapid decat Symfony.
Nu sunt un mare suporter al ideii de clasamente sau optimizari premature, insa citind articolul Framework Performance am fost curios sa vad cum se comporta Medick comparativ cu Rails, Django sau (in special) cu Symfony.
Exact ca in exemplul din articol, am creat o noua aplicatie – cookbook – cu Medick bazata pe tutorialul Ruby on Rails tutorial Rolling with Ruby on Rails.
Am pastrat si ideea de a genera un numar unic pe pagina de test folosind microtime. Nu stiu exact numarul de bytes serviti in testul prezentat, insa, cu Medick am avut fix 1000.
Test Hardware
- AMD Athlon™ 64 Processor 3000+ (Venice)
- 1 Gig RAM
- 40 Gig ATA 133 HDD (5400rpm)
Test Software
- OS: Mandriva Linux release 2006.0 (Official) for i586
- kernel: 2.6.12-18mdk (i686)
- stress-test software: Siege 2.65
Medick setup:
Consideratii
Majoritatea pachetelor sunt compilate din surse, poate pentru a mai compensa diferenta destul de mare intre hardware. Unele teste au fost rulate cu serverul X pornit, fapt ce a atras o penalitate de aproximativ 8% din CPU. In final insa, nu cred ca acest lucru a influentat rezultatele obtinute.
Apache/2.0.55 (mod_php)
Compilat cu gcc 3.3.6 utilizand comanda:
./configure --prefix=/wwwroot --enable-mods-shared=all --enable-so
MySQL 5.0.21
Compilat cu gcc 4.0.1 utilizand comanda:
./configure --prefix=/wwwroot
--with-mysqld-user=mysql
--localstatedir=/wwwroot/data
--disable-maintainer-mode --without-debug
Se foloseste my-medium.cnf, cu optiunile pentru InnoDB activate.
PHP 5.1.4
Compilat cu gcc 3.3.6 utilizand comanda:
./configure --prefix=/wwwroot
--with-pdo-mysql=/wwwroot
--with-mysql=/wwwroot
--with-apxs2=/wwwroot/bin/apxs
--enable-memory-limit
--enable-mbstring
--with-zlib
--with-gd
--with-jpeg-dir=/usr/include
--with-png-dir=/usr/include
--with-freetype-dir=/usr/include
--with-zlib-dir=/usr/include
--enable-gd-native-ttf
--enable-exif
--with-curl
Se foloseste php.ini-recommended.
APC-3.0.10
APC a fost compilat din surse folosind gcc 3.3.6 cu comanda:
./configure --enable-apc-mmap
--with-apxs=/wwwroot/bin/apxs
--with-php-config=/wwwroot/bin/php-config
APC a fost configurat conform instructiunilor de aici.
Medick-0.3.0pre1
Medick, versiunea oferita la download, cu nivelul de log setat la 3, pentru a simula conceptul de mediu de productie.
Pentru a nu creea un nou articol foarte lung si greu de urmarit, o sa revin maine cu rezultatele obtinute.
medick version 0.3.0pre1 was released today.
For download you can use one of berlios mirrors.
Please note that this version is not compatible with older versions.
Learn how to upgrade your medick applications to 0.3.0pre1 from this message posted on the internal development list.
Also, starting with this release, php 5.1.2 or higher is required.
This version adds a new validation API and fixes a minor bug in Request::toString method.
For a complete list of changes see the CHANGELOG file.
medick is a PHP 5 Web Framework (not a collection of PHP classes!) released under a BSD style LICENSE.
Medick 0.3.0pre1 Released, written by aurelian in
medick,
|
No Comments
Update: (11.07.2006)
Incepand cu medick 0.3.0pre1 sintaxa pentru validari a fost modificata.
Am corectat acest articol pentru a reflecta ultimile schimbari.
Vorbeam acum cateva zile despre detalii foarte tehnice legate de validarea obiectelor ActiveRecord in medick. Spuneam ca aceste validari au loc in filtrele before_*, insa pana acum nu am explicat povestea lor.
Din nou, un articol lung, ce poate servi insa ca documentatie pentru framework.
Filtrele ActiveRecord pentru medick sunt practic niste metode oferite de framework, dar implementate de utilizator prin care se poate interveni in cel putin doua puncte cheie din viata unui obiect ActiveRecord: inaintea sau dupa efectuarea unei operatii legate de baza de date cu acel obiect.
Aceste metode sunt grupate (pentru moment) in doua categorii: before si after.
Voi detalia filtrele before_, urmand ca intr-un articol viitor sa explic ce se intampla in filtrele after.
1) Filtre before_
Sunt 4 metode ce pot fi implementate, executate inainte de efectuarea unei operatii cu obiectul detinut. Aceste filtre sunt declarate ca metode cu vizibilitate protected si vor returna o valoare boolean , TRUE va permite continuare operatiei curente iar FALSE va intrerupe aceasta operatie.
Cele mai cunoscute utilizari includ: validarea anumitor proprietati ale obiectului curent, setarea de valori implicite pentru anumite campuri sau efectuarea unor operatii suplimentare declansate de crearea obiectului curent (db triggers).
Operatiile posibile (numele metodelor) sunt:
1a) before_insert
Executat inainte de inserarea obiectului in baza de date.
Poate cel mai bun exemplu este un obiect user care inainte de a fi creat, va trebui sa aibe proprietatea terms_and_conditions cu valoarea 1 pentru a semnala ca user-ul curent a fost de acord cu termenii si conditiile prezentate:
class User extends ActiveRecord {
protected function before_insert() {
// conditiile impuse nu au fost aceptate:
if ($this->terms_and_conditions != 1) {
// adaugam un mesaj de eroare:
$this->getField('terms_and_conditions')->addError('Conditiile nu au fost acceptate');
return FALSE;
}
// setarea unui camp cu valoare initiala:
$this->created_at= time();
}
[ ... ]
}
// utilizare (in controller de exemplu):
$user= new User();
$user->insert(); // filtrul este executat!
// sau:
$user->save(); // filtrul este si in acest caz executat!
1b) before_update
Este un filtru executat inaintea actualizarii unui obiect ActiveRecord.
class User extends ActiveRecord {
protected function before_update() {
[....]
// setarea unui camp cu valoare initiala:
$this->updated_at= time();
return TRUE;
}
[....]
}
// utilizare:
$user= User::find(1); // gaseste user-ul cu id=1
$user->update(); // filtrul este executat
// sau:
$user->save(); // filtrul este executat si in acest caz.
1c) before_save
Filtru executat inaintea salvarii obiectului curent in baza de date.
Poate contine, de exemplu, metode comune de validare atat in cazul in care obiectul curent este nou (creat cu insert) sau se incearca doar actualizarea acestuia.
class User extends ActiveRecord {
protected function before_update() {
$this->validates_presence_of('name');
return TRUE;
}
[....]
}
// utilizare:
$user= User::find(1); // gaseste user-ul cu id=1
$user->save(); // filtrul este executat
// sau
$user= new User();
$user->name= 'Mihai';
$user->save(); // filtrul este executat
1d) before_delete
Este executat inaintea stergerii obiectului curent din baza de date. Un exemplu bun de folosire este stergerea mesajelor detinute de utilizatorul (user-ul) curent.
class User extends ActiveRecord {
protected function before_delete() {
// gaseste mesajele detinute de acest user
$messages= Message::find('all', array('condition'=>'user_id=?'), array($this->id));
// sterge mesajele.
[....]
return TRUE;
}
[....]
}
// utilizare:
$user= User::find(1); // gaseste user-ul cu id=1
$user->delete(); // filtrul este executat
Cam astea sunt cateva detalii si metode mai intalnite pentru folosirea acestor filtre.
Foarte important: nu uita sa adaugi linia return true chiar la sfarsitul filtrului, in caz contrar php va returna in mod implicit false!
medick version 0.2.3 was released today.
For download you can use one of berlios mirrors or the .ro copy.
This is the “still alive” proof release! It includes minor changes and fixes to 0.2.2.
For a complete list of changes see the CHANGELOG file.
medick is a PHP 5 Web Framework released under a BSD style LICENSE.
Medick 0.2.3 Released, written by aurelian in
medick,
web
|
No Comments
Acesta este un articol destul de lung si poate plictisitor.
Se poate inscrie intr-o serie de articole cu numele Ce nu imi place la medick?
Validare in medick a obiectelor ActiveRecord inainte de salvarea in baza de date se face cu ajutorul filtrelor before_*.
Am tinut foarte mult sa am o sintaxa citibila si asemanatoare cu cea din rails.
Astfel, pentru un obiect ActiveRecord – denumit pentru exemplificare Person avand obligativitatea prezentei numelul si a adresei dar si unicitatea numelul – cineva poate scrie:
class Person extends ActiveRecord {
protected function before_save() {
$this->validates()->presence_of('name', 'address');
$this->validates()->uniqueness_of('name');
return TRUE;
}
[...]
}
In primul rand, php-ul are nevoie de linia return TRUE, fara aceasta – in momentul in care se incearca salvarea obiectului cu $person->save() – vom constata ca valoarea returnata in mod implicit este FALSE iar metoda save isi va termina (neanuntat!) executia.
Trecand peste aceasta, sintaxa pare ok. Functionalitatea este ok, chiar merge, in save rulez un “colector de errori” ce va intercepta validarile facute.
La o privire mai atenta, metoda validates returneaza un obiect de tip Validator. Acesta, abuzand de “magia” php, foloseste metoda __call pentru a intecepta apelurile catre metode nedefinite.
In __call, am adaugat conditii astfel incat in functie de numele metodei apelate se va incerca trimiterea apeluli mai departe catre metode cunoscute ale obiectului Validator.
Spre exemplificare, presence_of este redistribuita catre isEmpty cu parametru campul pe care vrem sa il validam, in cazul nostru isEmpty(camp name) si isEmpty(camp address). Daca valoare campului dat spre validare este egala cu ‘’ se adauga automat campului un mesaj de eroare (‘is empty’) si se returneaza TRUE(da, campul este gol).
Validator-ul meu stie pentru moment doar doua tipuri de verificari: uniqueness_of si presence_of.
Pentru a adauga un nou tip de validare (de exempul verificare lungimii unui camp: length_of) trebuiesc facute modificari directe in framework in metoda __call a obiectului Validator.
Adaugarea unui mesaj personalizat de eroare este o alta piedica, practic cineva ar trebui sa modifice manual mesajele trimise de Validator.
Revenind la filtrele before_*, am lasat pentru moment o portita de validare, utilizatorul putand adauga validari personalizate folosind de exemplu:
if (strlen($this->name) <= 3) {
$this->row->getFieldByName('name')->addError('should have at least 4 chars.');
}
pentru a valida dimensiunea campului name.
Intreaga procedura de validare a obiectelor ActiveRecord in medick este practic inutilizabila in cadrul proiectelor de tip mediu.
Validatorul meu, chiar daca functioneaza si arata bine, este practic inchis. Nu se pot schimba mesajele de eroare si nu se pot adauga alte tipuri de validari.
Vestea buna insa: sunt in cautarea unui nou design al API-uli ce se ocupa de validari. Am cateva ideii, momentan asezate doar pe hartie:
Voi adauga in clasa ActiveRecord metode directe de validare ce vor returna un descendent al obiectului Validator (transformat in obiect abstract):
[....]
protected function validates_presence_of() {
return new PresenceOfValidator($this, func_get_args());
}
[...]
class PresenceOfValidator extends Validator {
[...]
}
Noul Validator va avea metode prin care se vor putea seta parametrii aditionali, de exemplu pentru verificarea dimensiunii unui camp se va putea scrie:
$this->validates_length_of('name')->within(1,12);
sau pentru a adauga un mesaj de eroare personalizat:
$this->validates_presence_of('name')->message('%s trebuie completat!'); // => Name trebuie completat
Nu pot spune acum cand o sa modific API-ul de validare sau cum va arata el, sunt inca in cautare de solutii (doar la asta ma gandesc pe 41).
In mod sigur insa, medick are nevoie de un release cat mai curand.
Validarea obiectelor ActiveRecord, written by aurelian in
medick,
|
No Comments
Da, trebuie sa recunosc, de cateva zile lucrez (as freelance) la un proiect web ce va folosi medick.
Experienta aceasta va imbunatati cu siguranta calitatea frameworkului, in primul rand pentru ca in felul asta pot adauga noi facilitati – vad mai bine lipsurile – apoi, am o motivatie in plus: voi primi o suma de bani pentru proiectul respectiv.
Aplicatiea este destul de simpla: “un fel de” magazin, momentan doar de prezentare a produselor.
Aceste produse sunt caracterizate de un producator (has_one company) si de o categorie in care sunt inscrise (has_one category), pe langa proprietati simple de tipul pret, cantitate, nume sau descriere.
Am ales sa folosesc modelul Nested Set pentru a stoca arborele categoriilor tinand cont si de “target database”: MySQL 4.1.
Un articol foarte bun: Managing Hierarchical Data in MySQL de Mike Hillyer dar si prezentarea sa cu acelasi nume sustinuta la PHP Quebec 2005.
Arborele meu are un nod central numit root (exact ca in exemplul prezentat in articolul de mai sus, nod denumit 'ELECTONICS'), insa acest nod nu va fi afisat niciodata.
Cea mai mare bucurie a acestui proiect - pana acum - a fost data de transformarea arborelui rezultat in urma unui SELECT intr-o lista ne-ordonata, folosita, de exemplu, pentru a afisa un “site-map” sau pentru afisarea unui meniu de navigare.
De doua zile stau si admir rezultatul si avantajele acestui model:
un SQL SELECT si nici o recursivitate!
Selectul:
SELECT node.*, (COUNT(parent.name) - 1) AS depth
FROM categories AS node, categories AS parent
WHERE
node.lft BETWEEN parent.lft AND parent.rgt
AND parent.id !=1
GROUP BY node.name ORDER BY node.lft;
depth reprezinta “adancimea” in arbore a nodului curent sau distanta fata de primul nod (acesta are “adancime” 0)
parent.id!=1 pentru ca nu vreau primul nod (root) in lista rezultata.
Rezultatul este un ResultSet produs de creole.
Parcurgerea:
$last_depth = -1;
$output= '<ul>'; // rezultatul final
while($rs->next()) {
$current_depth = $rs->getInt('depth'); // adancimea nodului curent
// conditie cheie:
if ($last_depth > $current_depth) {
$output .= str_repeat('</ul></li>', ($last_depth - $current_depth));
}
$output .= '<li>' . $rs->getString('name');
// conditie echivalenta cu intrebarea hasChildren()?,
// urmata de getChilds() si parcurgerea recursiva
// a noului arbore
if ($rs->getInt('rgt') - 1 != $rs->getInt('lft')) {
$output .= '<ul>';
} else {
$output .= '</li>';
}
$last_depth = $current_depth;
}
echo $output . '</ul>';
Unde mai pui ca rezultatul este valid XHTML.
Lectura suplimentara:
Working with Graphs in MySQL (vezi si biografia atasata)
Joe Celko's Trees and Hierarchies in SQL for Smarties
Nested Set 2 Unordered List, written by aurelian in
general,
medick
|
No Comments
I’ve got some emails in the last days (like 2) from people asking about medick future.
They noticed that I was some how “on Rails” in the last weeks.
So I have decided to answer online on this question:
The development on medick is not closed and the medick project is not dead!
It’s just that I needed a brake from evil PHP way of doing things.
After 4 years of coding where almost 90% from my time went to PHP, the only chance for me to evolve as a programmer is to look from time to time to other programming languages.
Ruby is too cool to be ignored, starting with the community that they have, the release process that they are using and the super tools that you get in the same package as ruby it self.
Rails is the killer application for ruby. They are not advertising only a rapid development web framework, they are promoting best practices.
Back to medick, I have a lot of nice ideas for the future, I even try to implement some of those without committing them to repository.
For sure, major changes will be introduced starting with version 0.3:
- php 5.1.4 (or higher) will be required since I want to use some nice features added to the language,
- replace xml configuration file with a php script,
- performance improvements to ActiveRecord (cheap cache using static for query results),
- more options when using ActiveRecord validations and more Validators to be added on the framework,
- update unit-tests (at least a cleaning is needed) to reflect all the changes,
- more docs.
A roadmap (maybe is deprecated already?) is here.
Anyway, I cannot estimate now a relase date for version 0.3, I cannot even say if the development on 0.2.x is closed, but stay tuned, I will let anyone know when I will add new features to the framework and how to use them.
For questions or support on medick, you can contact me via the contact form. If you want to get involved in this project, just subscribe to the mailing list and start asking questions there.
On the other side, my rails pet project, marks is the first item on my todo list. If you don’t get it, “I’d rather be on rails (™)”.
0.3, on Medick future, written by aurelian in
medick,
|
No Comments
medick, the PHP Framework, has been released.
This is version 0.2.2 and for download, you can use one of berlios mirrors or the .ro copy. Click here if you preffer a zip package.
Changelog
With the help of creole, medick will try to escape everything that will go to the database using PreparedStatements
I have decided that medick should not take care about filtering any HTML input that commes as request parameter or from web forms.
This means that the HTML will be taken as it is.
If some will input nasty html tags:
<script>alert('foo');</script>
well, you will end up with a javascript alert message on you screen.
I think this is a nice feature to medick, since I don’t want to change from the framework any data that your application receives.
You can use some php functions for that in your models. Just hook the calls in your model before_* filters.
A short example:
class Article extends ActiveRecord {
protected function before_save() {
$this->title= htmlentities($this->title);
}
[....]
}
When I started to code on medick, one of my first goals was to hide all the PHP annoyances, to hide them from me because I will be the main user of this framework and then to hide them from my users. At one point I knew that I will face some of those annoyances, where I will loose more that 15 minutes to solve.
So, on my TODO list for release 0.2.2 I had:
An sql container for keeping PHP sessions.
I searched my HDD, knowing that I wrote something like this, and found it on an old backup folder:
[aurelian@gremlin ~]$ ll /mnt/win_d/30-07-2005/.../CreoleSession.php
-r-xr-xr-x 2 root root 4097 Mar 8 2005 /mnt/win_d/30-07-2005/.../CreoleSession.php*
Last accessed a year ago. Belive it or not, this class is doing his job very well on one of my older projects (with a primitive version of medick). On that server: PHP 5.0.5.
Anyway, I have started to modify this class to match my ISessionContainer interface, a piece of cake. Ended up with a nice class declaration:
class CreoleSessionContainer extends Object implements ISessionContainer
After that I had to remember what was the PHP function that will register this class as a session handler.
Since I’m not good at remember PHP function names, I started my search with session_start on PHP manual, after that I saw session-set-save-handler on the left side.
To test somehow, I altered my Session class and made a call to that function in my start method, just before session_start:
$container = new CreoleSessionContainer();
session_set_save_handler(array($container, 'open'),
array($container, 'close'),
array($container, 'read'),
array($container, 'write'),
array($container, 'destroy'),
array($container, 'gc'));
The result?
Fatal error: Exception thrown without a stack frame in Unknown on line 0
I knew that this is something really nasty, and my first thought was that a SQLException was thrown somehow form my container.
Back to code, I surrounded every sql call with nice try/catch blocks and added an echo to debug the Exception message. No result.
Back to manual:
Note: The “write” handler is not executed until after the output stream is closed. Thus, output from debugging statements in the “write” handler will never be seen in the browser. If debugging output is necessary, it is suggested that the debug output be written to a file instead.
So I replaced all the echo’s with $logger->debug calls. No result. Nothing on the log file.
Back to manual, a WARNING:
Write and Close handlers are called after destructing objects since PHP 5.0.5. Thus destructors can use sessions but session handler can’t use objects. In prior versions, they were called in the opposite order. It is possible to call session_write_close() from the destructor to solve this chicken and egg problem.
So, there was a chicken and egg thing. I had 5.1.2 installed, and yes, as opposite to many php coders, I was trying to save an object into the session.
On the manual, I read the first comment
That is not the way objects should be saved into session. You should not just assign the entire object to $_SESSION[‘myObj’] and hope for the best while waiting for the script to end and for the php internal engine to serialize your object, call destructors etc.
You should serialize your object beforehand by specifically calling serialize() on your object and assign the serialized string to a session key.
The second comment? even worse:
As posted here (http://marc.theaimsgroup.com/?l=php-general&m=113833844422096&w=2) the session module cannot handle objects anymore (tested in 5.1.2).
So, no objects into the session anymore?
Well, my friends, after 4 hours of digging (include this post also) my solution for medick is like this:
ActiveRecord::__sleep, do not close the database connection who knows in what order the objects are destroyed in PHP? Simple huh?
The result will be added soon is under version control.
4 hours on session, written by aurelian in
medick,
|
No Comments
In release 0.2.1 of medick, the check_box control from FormHelper was broken.
As a temporary fix, you have to explicitly check if the check_box was submitted or not in your controllers.
Let’s see a small sample.
I will assume that we have an article model with a status defined as INT (1) in the database. This status describes the article state: PUBLISHED or DRAFT.
The article model will look like:
class Article extends ActiveRecord {
const PUBLISHED= 1;
const DRAFT= 0;
[...]
}
On the controller side, I will define 2 methods: add, witch will print the form for adding an article and create that will save the article in the database.
class ArticleController extends ApplicationController {
// prints the form, and assign article template variable
public function add() {
$this->article = new Article();
}
// saves the article in the database
public function create() {
$this->article= new Article($this->request->getParameter('article'));
// explicit check:
if (!isset($this->params['article']['status'])) {
// the check box is not checked, so we define the
// default value for this case:
$this->article->status= Article::DRAFT;
} else {
// checked check-box:)
// default value for this case:
$this->article->status= Article::PUBLISHED;
}
// do actions on article, like save and the redirect if succes or render
// the form again if it`s a failure.
[...]
}
}
In the add view, we can use the FormHelper to create the check box entry for us:
[...]
<?=FormHelper::check_box($article,'status');?>
[...]
translated in HTML:
<input type="checkbox" id="article_status" name="article[status]" />
As I said, this is just a temporary solution untill I will have another ideea.
This includes adding a hidden field with the same name on the form, or anything else that will do.
Why this checkbox is causing all this troubles?
Because if is not checked, the article that we create at this line:
$this->request->getParameter('article');
will not receive the status as a request parameter.
The real pain it will be when one will need more than a simple checkbox, and I’m thinking about a use case where an article has_many categories and a checkbox control will be used for selecting in what categories the article fits.
While I mark this problem as fixed, I’m still open to improvements on how can I do this better.
FormHelper::check_box, written by aurelian in
medick,
|
No Comments
Ce nu merge?
- FormHelper::check_box
nu functioneaza, problema este sub investigatii si va fi fixata in curand.
- ActiveRecordHelper::error_messages_on
metoda nu este inca implementata, va fi insa in urmatorul release.
- Pastrarea unui obiect ActiveRecord intr-o sesiune are un comportament ciudat, metodele magice din php __wakeup si __sleep nu reflecta schimbarile pe care le-am adus in ultimul timp in ActiveRecord. Acest lucru va fi fixat in urmatorul release.
- Chiar daca rewrite este setat pe on, conditia de verificare $rewrite==0 este evaluata TRUE, deci URL-urile au inclus index.php.
- Validatorul uniqueness_of adaugat in filtrul before_filter() nu functioneaza corect cand se face update. Acest lucru va fi fixat in urmatorul release.
- Unit-testele nu au fost incluse, pentru ca testele legate de pachetul medick.configurator
nu au putut fi fixate la timp.
Ce lipseste?
- Un container sql pentru pastrarea sesiuni. Teoretic, ar trebui scrisa o implementare a interfetei ISessionContainer , adaugarea unei noi setari in fisierul de configurare si modificari minore in HTTPRequest si Session. Acest container va fi adaugat in urmatoarea versiune.
- Validari ale rutelor prin introducerea Route::requirements. Acestea vor fi adaugate in urmatoarea versiune.
Ce urmeaza in medick 0.2.2?
- Modificarile amintite mai sus.
- Mai multe Unit-Teste.
- Code Clean-Up in ActiveRecord si in ActionController.
- Inlocuirea include_once cu include (10x em@il), o problema pe care o sa o am in vedere.
Erata: medick-0.2.1, written by aurelian in
medick,
|
No Comments