23 декабря 2010
Критические замечания к CodeIgniter фреймворку
Это не пост гнева, а скорее желание помочь, кто будет наступать на грабли.Не буду много писать, текст будет интересен тем, кто уже освоил CodeIgniter и знаком со стандартными классами и принципами или только начинает на нём писать и ему предстоит столкнутся с граблями. Всё актуально для версии 1.7.2, хотя как погляжу в 2ке так же не поправили и всё прежнее.
Но последнее время так как много времени уходит на допиливание ряда проектов на этом фреймворке, то приходится встречаться всё с новыми и новыми проблемами, которые так или иначе очень похожи на баги или недоработки.
Сегодня уже был третий болт за неделю, что меня окончательно добивает. То ли я чего-то недопонимаю и это зачем-то сделано намерянно, то ли это реальные глюки.
1. Валидация форм (Form_validation) отправленных только через $_POST
Я конечно понимаю, что это суть фреймворка, что все запросы идут через _POST, но в настройках есть возможность включить например тот же _GET или даже допустим мы шлём форму через _POST но у нас только одно поле —
<input type="file name="file" />а внутри контроллера или модели есть желание повесить callback_ валидацию на проверку валидности например этого файла, его типа, его данных, допустим это Excel
Но увы, код
$this->form_validation->set_rules('file', 'File', 'callback_file_check');
if( $this->form_validation->run() === FALSE ){
...
}постоянно будет срабатывать в условии FALSE и валидация никогда не будет вызвана, причина простая, у разработчиков в голове не было такого варианта развития действий.
Заходим в файл класса libraries/Form_validation.php
function run($group = '')
{
// Do we even have any data to process? Mm?
if (count($_POST) == 0){
return FALSE;
}Ну с этим всё, 3 варианта действия у нас.
1. Расширить CI_Form_validation своим MY_Form_validation переписав эту проверку в методе run()
2. Добавить какую-нибудь беcсмысленную input type=«hidden» переменную с каким-нибудь значением, например для CSFR защиты
3. В лоб, залезть и переписать кусочек кода :)
Проблема простая и видно, что просто не учли всех вариантов использования класса.
Номер 2 проблема.
libraries/Cart — есть такой с 1.7.1 появившийся класс для работы с корзиной интернет магазина, можно класть товары, собирать их, доставать и т.п.
Но проблема, что нельзя положить например несколько раз подряд товар одного и того же вида, например хочу класть в корзину 1 футболку, погулять, потом вернуться и положить еще одну такую же футболку, такого же размера, цвета!
Почему? Да всё просто, опять же не предусмотрели, что не во всех магазинах человек хочет указывать кол-во товара руками и т.п. Он может например просто кнопочкой «положить товар» и через ajax очень много раз класть в корзину, набирая её с горкой например.
Каждый товар имеет уникальный rowid который складывается из хэша параметров товара и если он совпадает с уже имеющимся, просто перетирает старый.
Класс libraries/Cart.php метод _insert()
// генерация ключа
if (isset($items['options']) AND count($items['options']) > 0){
$rowid = md5($items['id'].implode('', $items['options']));
}else{
$rowid = md5($items['id']);
}
// стираем старые данные на этом месте и сливаем новые
unset($this->_cart_contents[$rowid]);
// Create a new index with our new row
$this->_cart_contents[$rowid]['rowid'] = $rowid;
// And add the new items to the cart array
foreach ($items as $key => $val){
$this->_cart_contents[$rowid][$key] = $val;
}согласитесь, не очень удобно, в магазинах ложить товар поштучно
Как варианты решения 2: расширить опять же класс и 2ой это нагло переписать, смотрите сами. Я изменил вот так вставку
// is it second put?
if( isset($this->_cart_contents[$rowid]) ){
$this->_cart_contents[$rowid]['qty'] += $items['qty'];
}else{
unset($this->_cart_contents[$rowid]);
// Create a new index with our new row ID
$this->_cart_contents[$rowid]['rowid'] = $rowid;
// And add the new items to the cart array
foreach ($items as $key => $val){
$this->_cart_contents[$rowid][$key] = $val;
}
}Недочет 3, который тоже очень портит жизнь особенно если у вас много внутренних вызовов внутри контроллера своих же методов с заполнением различных шаблонов и Views.
В чем проблема, простенький пример набрасываю: контроллер Article два метода
public function show($id){
$data = array( 'title' => 'hello' );
$this->template['show'] = $this->load->view( 'article/show', $data, TRUE );
$tags = array( 'tag1', 'tag2', 'tag3' );
$this->template['tags'] = $this->load->view( 'article/tags', $tags, TRUE );
$this->load->view( 'layouts/inside', $this->template ); // **
}Ну так вот в чем суть, что последний вызов шаблона будет знать о кучке других переменных например ему помимо $show, $tags будут еще доступны $title и массив $tags. Знаете ли мне кажется это не совсем удобно и правильно. Если еще в MVC это не так сильно будет мешать, а вот в применении HMVC то будет страшновато смотреть что там накопилось за время работы.
На заметку, память поедается методом vars и _ci_load обратите внимание в классе libraries/Loader, решений так же 2, переписать и расширить.
Я просто переписал в методе _ci_load
if (is_array($_ci_vars)){
$this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
}на строку вида
if (is_array($_ci_vars)){
$this->_ci_cached_vars = $_ci_vars;
}Не оптимально, но приемлимо получилось.
А вообще CodeIgniter, конечно был в своё время очень хорошим фреймворком, брал своей простотой, обилием библиотек, хорошей документацией и отличным сообществом, но в последнее какой-то период «застоя». Версия 2 топчется на месте, коммунити разваливается, да и вообще в мире выросло уже много не плохих альтернатив, я лично уже в предвкушении FuelPHP фреймворка от команды, что работала над CodeIgniter и PyroCMS.
Комментарии:0