Phalcon: Давайте учиться на примере

в 15:26, , рубрики: framework, mvc, phalcon, php

PHP MVC Framework — PhalconPHP
Совсем недавно на хабре уже упоминался PHP MVC Framework написанный на языке C, где были описаны его преимущества и недостатки. Этой статьёй я хочу продолжить знакомство с довольно интересным инструментом веб-разработчика — PhalconPHP.

Данная статья является вольным переводом базового урока, в котором будет рассмотрен процесс создания приложения с простой формой регистрации, а также разъяснены основные аспекты поведения фреймворка.

Лучший способ использовать это руководство – пройти его шаг за шагом.

Конечный результат можно найти на github.
Каркас приложения может быть автоматически сгенерирован при помощи инструментов разработчика, однако данная статья не описывает эту возможность.

Установка Phalcon PHP достаточно тривиальна, всё сводится к установке PHP расширения, которое можно скачать с официального сайта.

Установив Phalcon PHP проверьте наличие секции «Phalcon» в результатах вывода phpinfo() или выполните фрагмент кода ниже:

<?php

print_r(get_loaded_extensions());

Среди прочих расширений вы должны увидеть и phalcon:

Array
(
    [0] => Core
    [1] => libxml
    [2] => filter
    [3] => SPL
    [4] => standard
    [5] => phalcon
    [6] => pdo_mysql
)

Структура директорий

Phalcon не требует использования какой-либо определённой иерархии проекта, для разработки приложения вы можете использовать такую структуру с которой привыкли работать.

Для примера, в этом уроке мы будем использовать следующую структуру:

tutorial/
  app/
    controllers/
    models/
    views/
  public/
    css/
    img/
    js/

Заметьте, что вам не нужна директория вроде «library» для размещения фреймворка, Phalcon уже доступен из памяти и готов к использованию.

Красивые URL

Этот урок использует человекопонятные URLs (ЧПУ). ЧПУ не только полезны для поисковой оптимизации, но и позволяют пользователям проще запоминать ссылки. Поддержка ЧПУ вашим приложением не обязательна, вы вольны разрабатывать проект и без их поддержки.

Этот пример использует mod_rewrite для Apache и, исходя из нашей структуры директорий, нам потребуются два файла .htaccess: один в корне проекта, другой в публичной директории.

#/.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteRule  ^$ public/    [L]
    RewriteRule  (.*) public/$1 [L]
</IfModule>

Все запросы к приложению будут направлены в директорию public/. Этот шаг гарантирует, что внутренние папки проекта остаются скрытыми от публичного доступа, снижая угрозу безопасности.

Второй набор правил проверяет, существует ли требуемый файл. Если файл отсутствует, то веб-сервер преобразует запрос к необходимому для фреймворка виду.

#/public/.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

Примечание переводчика: с точки зрения как безопасности так и производительности эффективнее будет вынести приложение за пределы public_html, оставив доступными только изображения, js и css. Но не будем отклонятся от примера.

Начальная загрузка (bootstrap)

Первый файл, который необходимо создать — это скрипт инициализации. Этот файл реализует инициализацию компонентов, он служит основой приложения, предоставляя контроль над всем его поведением.

Bootstrap-файл public/index.php выглядит так:

<?php

try
{
    //Register an autoloader
    $loader = new PhalconLoader();
    $loader->registerDirs(array(
        '../app/controllers/',
        '../app/models/'
    ))->register();

    //Create a DI
    $di = new PhalconDIFactoryDefault();

    //Setting up the view component
    $di->set('view', function(){
        $view = new PhalconMvcView();
        $view->setViewsDir('../app/views/');
        return $view;
    });

    //Handle the request
    $application = new PhalconMvcApplication();
    $application->setDI($di);
    echo $application->handle()->getContent();

}
catch(PhalconException $e)
{
     echo "PhalconException: ", $e->getMessage();
}

Ниже мы разберём каждую часть этого файла подробней.

Автозагрузчик

Первая часть файла инициализации это регистрация автозагрузчика. Он используется для загрузки контроллеров и моделей. Например, мы можем зарегистрировать одну или несколько директорий контроллеров, повышая гибкость приложения. В нашем примере использован компонент PhalconLoader.

С его помощью можно загружать классы используя различные подходы, но в этом примере мы выбрали обнаружение классов на основе предопределенных директорий.

<?php

$loader = new PhalconLoader();
$loader->registerDirs(
    array(
        '../app/controllers/',
        '../app/models/'
    )
)->register();

Управление зависимостями

Работая с фреймворком Phalcon необходимо понять концепцию внедрения зависимости (Dependency injection, wiki). Это может показаться сложным, но на самом деле всё очень просто и практично.

Phalcon содержит механизм, который хранит компоненты, необходимые для работы приложения, и предоставляет доступ к ним по запросу фреймворка. Этим механизмом является класс PhalconDI, который выступает в роли связующего звена, объединяя различные компоненты для их совместной работы.

<?php

//Create a DI
$di = new PhalconDIFactoryDefault();

PhalconDIFactoryDefault наследник PhalconDI реализующий внедрение зависимостей. Он регистрирует большинство стандартных компонентов фреймворка. Таким образом, мы не должны регистрировать их один за другим. При необходимости можно без проблем заменить его собственной реализацией.

Следующим шагом мы регистрируем компонент «view». Так как файлы представления не являются классами, их нельзя подгрузить с помощью автозагрузчика, поэтому мы должны указать их расположение.

<?php

//Setting up the view component
$di->set('view', function(){
    $view = new PhalconMvcView();
    $view->setViewsDir('../app/views/');
    return $view;
});

В последней части этого файла регистрируется компонент PhalconMvcApplication. Его цель заключается в инициализации окружения запроса, обработке маршрута и выполнении соответствующего запросу действия. Он получает ответ от контроллера и возвращает его, когда процесс будет завершен.

<?php

$application = new PhalconMvcApplication();
$application->setDI($di);
echo $application->handle()->getContent();

Как видите, файл инициализации достаточно прост и у нас нет необходимости подключать какие-то дополнительные файлы. Мы подготовили почву для гибкого MVC приложения уложившись менее чем в 30 строк кода.

Контроллер

По умолчанию Phalcon ищет контроллер и его действие с именем «Index». Оно будет выполнено, если в запросе не указаны контроллер и действие. Самый простой контроллер выглядит таким образом:

<?php

class IndexController extends PhalconMvcController
{
    public function indexAction()
    {
        echo "<h1>Hello!</h1>";
    }
}

Класс контроллера имеет суффикс «Controller», а его действие должно иметь суффикс «Action». Если открыть приложение в браузере вы увидите что-то такое:

image

Поздравляю, вы летаете с соколом! (Прим. переводчика: Phalcon созвучно с англ. Falcon — сокол*)

Представление (View)

Отправка вывода на экран из контроллера бывает оправданным, но так делать не стоит. Необходимые данные должны быть переданы представлению, ответственному за отображение на экране. Phalcon будет искать представление в файле с тем же названием, что и последнее выполненное действие, в директории с названием как у последнего выполненного контроллера. В нашем случае это app/views/index/index.phtml:

<?php echo "<h1>Hello!</h1>";

А сам контроллер (app/controllers/IndexController.php) теперь содержит пустое действие:

<?php

class IndexController extends PhalconMvcController
{
    public function indexAction()
    {
    }
}

Представление обрабатывается автоматически после завершения работы действия. Вывод в браузере должен остаться прежним.

Форма регистрации

Изменим представление app/views/index/index.phtml, добавив в него ссылку на другой контроллер «signup»:

<?php

echo "<h1>Hello!</h1>";

echo PhalconTag::linkTo("signup", "Sign Up Here!");

Сгенерированный HTML-код отобразит тег <a> с ссылкой на новый контроллер:

<h1>Hello!</h1> <a href="/test/signup">Sign Up Here!</a>

Чтобы сгенерировать ссылку был использован класс PhalconTag. Этот вспомогательный класс позволяет строить HTML в соответствии со стандартом фреймворка. Здесь можно найти более подробное описание генерации HTML кода.

image

Так выглядит новый контроллер «Signup» (app/controllers/SignupController.php):

<?php

class SignupController extends PhalconMvcController
{
    public function indexAction()
    {
    }
}

Пустое действие «indexAction» направляет прямиком к представлению с формой (app/views/signup/index.phtml).

<?php use PhalconTag; ?>

<h2>Sign using this form</h2>

<?php echo Tag::form("signup/register"); ?>

 <p>
    <label for="name">Name</label>
    <?php echo Tag::textField("name") ?>
 </p>

 <p>
    <label for="name">E-Mail</label>
    <?php echo Tag::textField("email") ?>
 </p>

 <p>
    <?php echo Tag::submitButton("Register") ?>
 </p>

</form>

Открыв этот контроллер в браузере вы увидете что-то подобное:

image

PhalconTag предоставляет полезные методы для создания элементов формы.
В метод PhalconTag::form мы передали путь к контроллеру/действию приложения, которое будет обрабатывать форму.

Нажав на кнопку «Register» вы увидите исключение брошенное из фреймворка, указывающее на отсутствие действия «register» в контроллере «signup».

PhalconException: Action “register” was not found on controller “signup”

Реализовав это действие мы избавимся от исключения:

<?php

class SignupController extends PhalconMvcController
{
    public function indexAction()
    {
    }

    public function registerAction()
    {
    }
}

Снова отправив форму вы увидите пустую страницу.

Введённые пользователем имя и email должны быть сохранены в базе данных. В соответствии с принципами MVC, взаимодействие с базой данных должно осуществляться моделью приложения, чтобы обеспечить чистый объектно-ориентированный код.

Модель

Phalcon приносит первую ORM для PHP, полностью написанную на языке Си. Вместо увеличения сложности разработки, это упрощает её.

Прежде чем создать нашу первую модель, нам нужно иметь таблицу в базе данных. Простая таблица для хранения зарегистрированных пользователей может выглядеть так:

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(70) NOT NULL,
  `email` varchar(70) NOT NULL,
  PRIMARY KEY (`id`)
);

Модель должна быть расположена в директории app/models.
Так будет выглядеть модель, предоставляющая доступ к таблице «users»:

<?php

class Users extends PhalconMvcModel
{
}

Соединение с БД

Для того, чтобы иметь возможность использовать соединение с базой данных и получить доступ к данным через модели, мы должны указать настройки соединения в файле инициализации. Подключение к базе данных это просто очередной компонент, который в последствии могут использовать и другие компоненты.

Дополненный bootstrap файл (public/index.php) будет выглядеть так:

<?php

try {

    //Register an autoloader
    $loader = new PhalconLoader();
    $loader->registerDirs(array(
        '../app/controllers/',
        '../app/models/'
    ))->register();

    //Create a DI
    $di = new PhalconDIFactoryDefault();

    //Set the database service
    $di->set('db', function(){
        return new PhalconDbAdapterPdoMysql(array(
            "host" => "localhost",
            "username" => "root",
            "password" => "secret",
            "dbname" => "test_db"
        ));
    });

    //Setting up the view component
    $di->set('view', function(){
        $view = new PhalconMvcView();
        $view->setViewsDir('../app/views/');
        return $view;
    });

    //Handle the request
    $application = new PhalconMvcApplication();
    $application->setDI($di);
    echo $application->handle()->getContent();

} catch(PhalconException $e) {
     echo "PhalconException: ", $e->getMessage();
}

Теперь наши модели готовы работать и взаимодействовать с остальной частью приложения.

Сохранение данных используя модель

Наш следующий шаг: получение данных из формы и их запись в таблицу.
Дополним действие «register»:

<?php

class SignupController extends PhalconMvcController
{
    public function indexAction()
    {
    }

    public function registerAction()
    {
        //Request variables from html form
        $name = $this->request->getPost("name", "string");
        $email = $this->request->getPost("email", "email");

        $user = new Users();
        $user->name = $name;
        $user->email = $email;

        //Store and check for errors
        if ($user->save() == true) 
        {
            echo "Thanks for register!";
        }
        else
        {
            echo "Sorry, the following problems were generated: ";
            foreach ($user->getMessages() as $message)
            {
                echo $message->getMessage(), "<br/>";
            }
        }
    }
}

Никогда нельзя доверять данным полученным от пользователя. Данные, переданные в наше приложение должны пройти валидацию/фильтрацию. Это сделает приложение более защищенным от атак на подобии SQL инъекций.

В нашем приложении мы применяем фильтр «string» к введённому имени и фильтр «email» к электронному адресу чтобы убедиться, что пользователь не прислал нам какие-либо вредоносные символы.

Компонент PhalconFilter делает эту задачу элементарной, так как он внедряется из контейнера зависимостей в вызов метода getPost.

Далее мы создаём экземпляр модели Users. Public свойства модели соответствуют полям таблицы users. Установив значения новой модели и вызвав метод save() мы производим запись в базу данных. Метод save() возвращает логическое значение, которое информирует нас о том, успешно ли была произведена запись.

Дополнительная валидация происходит автоматически для полей, которые обозначены как not null (т.е. являются обязательными). Если при отправке формы оставить поля незаполненными, то в браузере вы увидите сообщение:

Sorry, the following problems were generated: name is required
email is required

Заключение

Этот очень простой урок призван показать как легко начать разрабатывать своё приложение на фреймворке Phalcon PHP. Тот факт, что Phalcon является расширением к PHP написанным на C, совершенно не противоречит простоте разработки.

Я приглашаю вас продолжить изучение руководства, которое откроет для вас дополнительные возможности предлагаемые Phalcon!

___
* Сокол самая быстрая птица, и вообще живое существо, в мире. Но, справедливости ради, стоит отметить, что в горизонтальном полёте сокол уступает стрижу.

Автор: Agent_J

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js