piątek, 6 lutego 2009

A potem inni gadaja, że CakePHP to kicha

Jakoś mnie tak ruszyło strasznie :) Właśnie w niejakim serwisie www.switchonthecode.com ( pierwszy raz o nim słyszę, może jestem cofnięty ). Pojawiła się któraś już z kolei część tutoriala dotyczącego CakePHP. Jako, że generalnie zupełnie mnie ten tutorial nie interesuje postanowiłem jedynie przewinąć się przez całość, żeby zobaczyć co tam chłopaki klecą. No i się zaczęło. Mógłbym teraz zacząć się uzewnętrzniać ale ograniczę się do fragmentów kodu.
echo $html->tableHeaders(
array(
'Product ID',
'Product',
'Description',
'Price'
)
);

foreach($data as $product)
{
echo $html->tableCells(
array(
array(
$product['Product']['product_id'],
$product['Product']['product_name'],
$product['Product']['product_desc'],
$product['Product']['product_price']
)
)
);
}

Zacznę lajtowo bo to nie jest błąd ale moim zdaniem zupełnie zbyteczna rzecz. Tworzenie table za pomocą helperów. Czy naprawdę jest to tak kosmicznie potrzebne? Super, że CakePHP ma taki helper ( ma go pewnie dlatego, że inne frameworki też taki mają ). Ale po kiego grzyba go używać ? Podobnie jest z helperami do tworzenia linków:
echo $htm->link('gdzieś tam','/cos/tam'); 
- super ale
gdzieś tam // echo Router::url('/cos/tam');
ani nie jest dłuższe ani bardziej skomplikowane - jest za to szybsze! No i jeszcze można wymienić tworzenie obrazków, list, divów i całej reszty. Nie musisz, nie używaj!

echo $form->input('product_name');

Zawsze podawaj nazwę pola wraz z modelem, czyli Product.product_name ( pomijam fakt bezsensownej nazwy pola ). Przy formularzach dotyczących pojedyńczego modelu może wydawać się to bezsensowne ale jak pojawi się pole id i potem w zapytaniu wyciągane będzie pole id innego modelu to będzie płacz.

function add()
{
if(isset($this->data))
{
$this->Product->set($this->data);

if ($this->Product->validates())
{
if($this->Product->save())
$this->Session->setFlash('Data Saved Successfully!');

$this->redirect(array(
'controller' => 'products',
'action' => 'index'
)
);
}
}
}

Zacznijmy od
if(isset($this->data))
. Może się nie znam ale jak w klasie zdefiniowane jest
var $data = array();
to imho
isset($this->data);
wywali TRUE. Dalej przejdźmy do
$this->Product->set($this->data);
osobiście użyłbym metody create, no ale tak też działa. Dalej mamy totalną bzdurę
 if ($this->Product->validates())
. Jeżeli autor tutoriala raczyłby zajrzeć do API to pewnie nie sprawiłoby mu problemu przeczytanie dwu zdaniowego opisu metody save gdzie jest wyraźnie napisane
By default, validation occurs before save.

Nie ma więc najmniejszego sensu dodawanie tej linijki.

Naturalnie nie są to gigantyczne błędy ale uczą one nowych użytkowników złych zasad pisania kodu. Nie da się zrobić tak, żeby ktoś sam nie zagląda do API i book.cakephp.org napisał coś z czego można się czegoś nauczyć.

Dlatego jeszcze raz:

czwartek, 5 lutego 2009

PHP on Rails - chyba trzeba jeszcze poczekać.

Jakiś (znaczny ) czas temu dość intensywnie obserwowałem próby przeniesienia magii Ruby on Rails do PHP. Naturalnie można powiedzieć, że CakePHP też coś takiego robi ale na chwilę obecną wydaje mi się, że główne założenia były podobne ale teraz Cake idzie już swoją drogą. Poza CakePHP na arenie trzymały się jeszcze dwa frameworki : Akleos i PHP on Trax. Niestety z tego co widzę teraz to raczej nic z nich nie będzie. Akleos stara się przenieść możliwości Ruby on Rails jak najdokładniej. Jednak moim zdaniem robienie tego, patrząc się nieustanie czy się nie sypie w PHP4 jest drogą do do nikąd. Co do PHP on Trax tutaj nie będę się długo rozwodził, wystarczy spojrzeć na aktywne tickety.
Szkoda, bo jestem dość ciekawy co mogłoby wyjść z takiego frameworka :)

CakePHP, zgrzyt w SecurityComponent

Dostępny w CakePHP SecurityComponent to bardzo fajna sprawa. Szczególnie przydatną funkcją tego komponentu jest możliwość zwiększenia bezpieczeństwa formularzy tworzonych przy użyciu FormHelper. Jak wiadomo standardowo Cake w momencie gdy wywoływana jest metoda save modelu przyjmuje cała tablice z danymi które zostaną zapisane w bazie. Nie jest on jednak w stanie sprawdzić czy ktoś przypadkiem nie dopisał do formularz za pomocą np. FireBug'a jakiegoś dodatkowego pola którego dopisywać nie powinien. Oczywiście można w metodzie save dopisać listę dopuszczalnych pól ale jest to imho bardzo niewygodne. W tym momencie z pomocą przychodzi SecurityComponent. Poprzez proste dodanie go do aplikacji:
public $components = array('Security');
w momenci gdy tworzony będzie dowolny formularz doda on do niego token który będzie zawierał zakodowaną informację na temat pól jakie znajdują się w formularzu. Wszystko pięknie tyle, że podczas tworzenia tokenu Cake zakłada, że pola ukryte czyli takie które mają type = hidden nie będą zmieniały wartości. I tu pojawia się problem bo co zrobić jak ktoś wstawił sobie w formularzu kalendarz albo mapę Google i przed wysłaniem formularza chce zapisać w ukrytych polach nowe wartości? Za pewne można tworzyć zwykłe input'y i ukrywać je CSS'em ale nie o to chodzi. Naturalnie można temu zaradzić korzystając z możliwości ustawienia dla SecurityComponent wartości disabledFields:
$this->Security->disabledFields = array('Model.pole_1','Model.pole_2');
Wszystko byłoby pięknie gdyby nie fakt, że informację taką trzeba zawrzeć w metodzie beforeFilter() co trochę komplikuje sprawę w momencie gdy różne dane z jednego modelu edytujemy w różnych akcjach. Pewnie, że można dodać wszystkie pola jednocześnie ale czasami może przecież zdarzyć się tak że w jednej akcji na jakieś pole nie zwracamy uwagi a w innej w zależności od tego jaką ma ono wartość uzależniamy jakieś tam konkretne działania.
I to właśnie jest mój zgrzyt który naturalnie można obejść na milion sposobów w 2 minuty, tworząc np. tablicę zawierającą nazwy akcji oraz listę pól jakie mają być dopisane do disabledFields i w beforeFilter na podstawie nazwy akcji jaką chcemy wywołać dopisywać je do SecurityComponent.