Внезапная история из прошлого! Дело было так. Несмотря на то, что я программист «немного другого толку», обратились ко мне со стандартной просьбой – сделать сайт. Обычно я не берусь за подобные дела, но в этот раз решил немного подзаработать, тем более что это был не сайт-визитка или интернет-магазин, а нормальный сайт с базой некоторых объектов, объекты добавляются-редактируются-удаляются (аля CRUD) и с ними необходимо выполнять некоторые операции. О! подумалось мне, да это идеальная задача для (название фреймворка скрыто) и после всяческой бухгалтерии я незамедлительно приступил к делу.
Собственно дальше ничего интересного и необычного так и не произошло. Спустя какое-то время заказчику был продемонстрирован сайт. И… он остался доволен. Очень неожиданное завершение истории.
Правда, появилась небольшая как бы просьба. Файловый менеджер, тот, с помощью которого на сайт в статью можно вставить картинку, ему не понравился. Вот хотелось ему чтобы всё как-то проще было. А тут и кнопок целых 20! Да и действий много. А нужно-то всего-навсего загрузить картинку на сервер и вставить на страничку. Ну ладно, подумал я, их же целый интернет, да и сам я много раз делал подобные решения. Но один страшен, как чёрт, другой по одному файлу загружает за раз, а вот третий ничё так вроде, но платен. В общем, история завершилась быстро, созданием простенького файлового менеджера с нуля. Но как-то сиделось мне, да и взгрустнулось. И выпил я (сока с мякотью, конечно). И открыл IDE и понеслось…
Поправил я код, добавил туда кучу некоторых особенностей и написал эту статью, в которой попробую рассказать, в отличие от кучи мануалов, никак сделать блог, а как сделать файловый менеджер на Silex + Kendo UI. Без БД, без просмотрщика и редакторов и без прочей «шелухи».
Сперва начну с того, что попытаюсь объяснить, почему я выбрал именно эти инструменты (фреймворки).
Silex – микрофреймворк, про который я много раз слышал отзыв: “Так в нём же нету нихрена!”. А вот это неправда, Silex – вполне логичное решение, а заключалось оно в том, чтобы взять огромный такой Symfony2 и удалить папку vendors. Совсем. Придумали же ведь Composer – «инструмент», про который много уже писали, а умеет он, на основе содержимого файлика composer.json взять и скачать актуальные версии нужных библиотек (вендоров – vendors). Нужен нам ORM для доступа к БД, любим мы шаблонизатор TWIG, хотим в redis-ке хранить значения. Пропишем в composer.json нужное, выполним команду php composer.phar install и вот Silex не такой уж и никакой.
А вот для файлового менеджера он подходит куда как лучше, чем некоторые другие громоздкие решения.
Нужно определиться, что нам будет нужно от silex:
1) Конечно, решение на популярном фреймворке само по себе уже хорошо
2) Работа с сессиями
3) Работа с ответами (response и redirect)
4) Шаблонизатор twig
Немного дополню, почему я так люблю twig и всячески склоняю других его использовать. Я не верстальщик, но очень часто мне приходится работать в шаблонами (view) в привычном для php виде: т.е. использовать вставки из php. «php мощный, он сам себе шаблонизатор!» — повторяют ребята напротив. Так-то оно да, но он слишком мощный шаблонизатор. Я много раз ловил себя на мысли, что я пишу в шаблоне логику! А этого делать категорически нельзя! Так вот twig заставляет переосмыслить процесс создания шаблонов. Он достаточно мощный, чтобы уметь делать многое, и в то же время он оставляет идеи «попрограммить» в шаблоне.
Ну ладно, с php фреймворком решили — пускай будет. А почему kendo ui? Он же большой? Ну да, он действительно не маленький. Но, во первых-сайт который я делал уже использовал kendo, а во-вторых решение на этом JS фреймворке выглядит красиво. Из больших (известных) решений есть ещё ExtJS, но к нему я испытываю стойкую нелюбовь. Пахнет он плохо, и не красивый, имхо.
Что нам нужно от kendo:
1) window
2) splitter
3) uploader
4) menubar
5) treeview
Кстати, если взять сторонние js либы для таких целей, то получится уже не слишком маленькой решение.
Теперь попробую описать работу приложения. Прочитать код, я думаю, вы сможете и без меня, поэтому сосредоточусь на вещах, которые считаю более важными.
Response
У Symfony2 и конечно же у Silex есть очень удобная для работы особенность – они позволяют управлять исходящими (response) запросами. Данное приложение активно использует javascript, а js (в частности jquery ajax), может по-разному реагировать на ответ от приложения. Другими словами, если ajax функция получит нормальный ответ с кодом 200 – она отреагирует так-то, а если ошибку – по-другому. Например, jquery функция ajax может обрабатывать методы onSuccess (ответ 200 OK) и onError(не 200, а например, 500) (onSuccess и онError с недавних пор — done и fail). А с помощью вендора HttpFoundationResponse можно, как раз, отправить ответ с нужным кодом.
Где это используется – пытаемся сохранить файл (загрузить) в файловой системе. Но системный администратор, что-то там намудрил, и вместо пользователя www-data папка стала принадлежать пользователю root. Значит, сохранить файл мы не сможем – не хватает прав. Запишем полученную ошибку в переменную $this->error. А в функции-обработчике действия (сохранений картинки) сделаем так:
if ($save->handleUpload($sPath, $_thumbPath)) {
return new Response('', 200);
} else {
return new Response($save->getError(), 200);
}
Где, handleUpload – функция которая сохраняет файл, если операция удалась – вернёт TRUE, в противном случае FALSE.
Namespaces
Silex старается использовать все новшевства php, и в частности активно использует namespaces.
В принципе, можно использовать и обычный include, но это как-то не кашерно. Воспользуемся способом, который предлагает Silex, а тот в свою очередь с недавнего времени переложил функцию «регистрации адресного пространства» на composer.
И так. В нашем файловом менеджере можно выделить две логические части:
1) работа с файловой системой;
2) сохранение файлов и генерация превьюшек для изображений.
Создадим два класса: class Files {} и class Save {}. Каждый класс будет находиться в одноимённом файле в папке: /src/Fm/Components. Чтобы наше приложение понимало откуда нужно загружать эти файлы, пропишем в composer.json:
"autoload":{
"psr-0":{
"Fm" : "src/"
}
}
А теперь выполним команду:
php composer.phar update
Теперь можно использовать наши классы, но перед этим не забываем объявить их
use FmComponentSave
use FmComponentFiles
Оценить прелесть использования namespaces можно только в большом приложении, но тем не менее, нужно стараться использовать «правильные» методы. Ведь очень часто бывает, что если пренебречь такой, казалось бы малостью, позже может получиться так, что приложение разрослось и уже поздно думать о рефакторинге, и дешевле его переписать с нуля.
Depency Injecting
Следующая особенность фремворка Silex – вездесущий Depency Injecting. Если вы слышали об оном из Symfony2 может показаться, что это какая-то страшнейшая и мутнейшая хня, которая нужна только в Entrprise. И вот снова это мнение не верное.
1) Все тексты о DI – сплошь корявый промтовский перевод с английской документации, которая генерировалась в phpDocumentaror-е
2) Люди, которые работают в этом самом Entrprise, говорить простыми словами не могут или же не хотят, потому что что-то знают. IT буддисты.
Вернусь к DI. Класс Files() много где используется в коде. Если работать по старинке, то в каждом действии, придётся создавать новый объект new Files(). DI позволяет создать объект только один раз:
$app['files'] = function() {
return new Files();
};
И позже уже иметь его копию обращаясь к $app['files']. Но, важно помнить, что:
$app['files']->getFiles($dir); //получаем список файлов в private $_files;
$app['files']->getFolderFiles(); //геттер, возвращает массив $_files;
Не сработает! Потому что, нужно делать так:
$class = $app['files'];
$class->getFiles($dir); //получаем список файлов в private $_files;
$class->getFolderFiles(); //геттер, возвращает массив $_files;
Другими словами, при каждом обращении к $app['files'] будет создана новая копия «сервиса». Новый «сервис» можно создать и так:
$app['some_service'] = $app->share(function () {
return new Service();
});
Тогда в процессе выполнения приложения всегда будет одна его копия.
Файловый менеджер выложен на Github.
В этой статье не рассмотрена библиотека kendo ui. В принципе, если будет желание — можно сделать беглый её осмотр, с особенностями, которые затрагивают тему файлового менеджера.
Автор: Zazza