Создание блога на Symfony 2.8 lts [ Часть 2 ]

  • Tutorial





Страница с контактной информацией: валидаторы, формы и электронная почта



В этой части:

1. Валидаторы
2. Формы
3. Конфигурация Бандла

Проект на Github

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


Страница контактов


Маршрутизация


Как и со страницей “About” созданной в предыдущей главе, мы начнем с определения маршрута для страницы контактов. Откройте файл маршрутизации BloggerBlogBundle расположенный в
src/Blogger/BlogBundle/Resources/config/routing.yml
и добавьте следующее правило маршрутизации.

# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_contact:
    path:  /contact
    defaults: { _controller: "BloggerBlogBundle:Page:contact" }
    requirements:
        methods:  GET


Здесь нет ничего нового, правило действует для шаблона /contact, метод HTTP GET и выполняет функцию contactAction в контроллере Page в нашем бандле BloggerBlog.

Контроллер


Давайте добавим функцию для страницы Контактов в контроллер Page нашего бандла BloggerBlog который находится в src/Blogger/BlogBundle/Controller/PageController.php


class PageController extends Controller
{
    //..

    public function contactAction()
    {
        return $this->render('BloggerBlogBundle:Page:contact.html.twig');
    }

}

Сейчас эта функция очень проста, она лишь выводит шаблон для страницы контактов. Мы вернемся к контроллеру позже.

Отображение


Создайте шаблон:

src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig


И добавьте следующее содержание:

{# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}


{% block title %}Contact{% endblock%}

{% block body %}
    <header>
        <h1>Contact symblog</h1>
    </header>

    <p>Want to contact symblog?</p>
{% endblock %}



Этот шаблон также довольно прост. Он расширяет шаблон layout, переопределяет заголовок и определяет некоторый контент для блока body.

Cсылки на страницы

Наконец, мы должны обновить ссылки в шаблоне приложения, чтобы добавить ссылку на страницу контактов app/Resources/views/base.html.twig

#app/Resources/views/base.html.twig
            {% block navigation %}
                <nav>
                    <ul class="navigation">
                        <li><a href="{{ path('BloggerBlogBundle_homepage') }}">Home</a></li>
                        <li><a href="{{ path('BloggerBlogBundle_about') }}">About</a></li>
                        <li><a href="{{ path('BloggerBlogBundle_contact') }}">Contact</a></li>
                    </ul>
                </nav>
            {% endblock %}


Если вы перейдёте по адресу http://localhost:8000 и нажмёте на ссылку «Contact» в навигационной панели, вы увидите очень простую страницу контактов. Теперь у нас есть правильно настроенная страница и самое время, поработать с формой. Это включает в себя 2 отдельные части: Валидаторы и непосредственно сама Форма. Прежде чем мы сможем обратиться к концепции Валидаторов и Форм, мы должны подумать о том, как мы будем обрабатывать данные из запроса.

Сущность Contact


Давайте начнём с создания класса, который представляет запрос от пользователя. Мы хотим, принять некоторую базовую информацию, такую как имя, тема и тело запроса. Создайте новый файл src/Blogger/BlogBundle/Entity/Enquiry.php и вставьте в следующее содержание:
<?php

// src/Blogger/BlogBundle/Entity/Enquiry.php

namespace Blogger\BlogBundle\Entity;


class Enquiry
{
    protected $name;

    protected $email;

    protected $subject;

    protected $body;

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param mixed $email
     */
    public function setEmail($email)
    {
        $this->email = $email;
    }

    /**
     * @return mixed
     */
    public function getSubject()
    {
        return $this->subject;
    }

    /**
     * @param mixed $subject
     */
    public function setSubject($subject)
    {
        $this->subject = $subject;
    }

    /**
     * @return mixed
     */
    public function getBody()
    {
        return $this->body;
    }

    /**
     * @param mixed $body
     */
    public function setBody($body)
    {
        $this->body = $body;
    }

}

Совет (если вы используете IDE PHPStorm)
У вас есть возможность генерировать геттеры и сеттеры автоматически.

Для этого:

1. Нажмите на правую кнопку мыши в файле (или комбинацию alt+insert), выберите Generate



2. Далее Getters and Setters



3. Выделите все и нажмите ОК.





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

Заметка

Давайте поговорим о том, как используются пространства имён в Symfony2. Класс сущности который мы создали задаёт пространство имён Blogger\BlogBundle\Entity. Так как Symfony2 поддерживает стандарт автозагрузки PSR-0 пространство имён указывает непосредственно на структуру файлов бандла. Класс сущности Enquiry находится в src/Blogger/BlogBundle/Entity/Enquiry.php, что обеспечивает Symfony2 правильную автозагрузку класса.
Каким образом Symfony2 автозагрузчик понимает, что пространство имен Blogger находится в каталоге src? Это обеспечивается благодаря конфигурациям автозагрузчика app/autoload.php

/**
 * @var ClassLoader $loader
 */
$loader = require __DIR__.'/../vendor/autoload.php';

AnnotationRegistry::registerLoader(array($loader, 'loadClass'));

return $loader;



Он регистрирует все пространства имён которые не были зарегистрированы. Так как пространство имен Blogger не зарегистрировано, Symfony2 автозагрузчик будет искать необходимые файлы в директории src.
Автозагрузчик и пространство имен очень мощная концепция в Symfony2. Если вы получаете ошибки, где PHP не может найти классы, вероятно, у вас есть ошибка в вашем пространстве имен или в структуре папок. Вы не должны поддаваться искушению исправить это с помощью РНР require или include включения.



Формы


Давайте создадим форму.

Symfony2 поставляется с очень мощным инструментом для работы с формами. Как и все компоненты Symfony2, он может быть использован за пределами Symfony2 в других проектах. Компонент работы с Формами доступен на GitHub. Мы начнем с создания AbstractType класса, который представляет форму запроса. Мы могли бы создать форму непосредственно в контроллере, а не возиться с этим классом, однако отделение формы в отдельный класс позволяет повторно использовать форму во всем приложении. Он так же позволяет не загромождать контроллер. Контроллер должен быть простым.

EnquiryType

Создайте новый файл src/Blogger/BlogBundle/Form/EnquiryType.php и добавьте следующее содержание:

<?php

namespace Blogger\BlogBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EnquiryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name', TextType::class);
        $builder->add('email', EmailType::class);
        $builder->add('subject', TextType::class);
        $builder->add('body', TextareaType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {

    }

    public function getBlockPrefix()
    {
        return 'contact';
    }
}

Совет (если вы используете IDE PHPStorm)
Если вы используете IDE PHPStorm c плагином Symfony то создание класса EnquiryType будет еще проще

Нажмите правой кнопкой мыши на папке бандла, выберите New -> Form (или нажмите комбинацию Alt + Insert и выберите Form)



затем введите название EnquiryType и добавьте недостающие строки как описано выше ( обратите внимание, последний метод должен быть getBlockPrefix )



Класс EnquiryType представляет интерфейс FormBuilderInterface. Этот интерфейс используется классом FormBuilder. Класс FormBuilder это ваш лучший друг, когда дело доходит до создания форм. Он способен упростить процесс определения полей на основе метаданных. Поскольку наша сущность Enquiry очень простая мы не будет пока определять метаданные, так что FormBuilder будет выводить значения по умолчанию.

Заметка

Здесь нужно упомянуть, что метод getBlockPrefix должен возвращать уникальный идентификатор.

Создание формы в контроллере



Мы определили сущности Enquiry и EnquiryType, теперь мы можем обновить функцию contact, чтобы использовать их. Замените содержимое функции, расположенной src/Blogger/BlogBundle/Controller/PageController.php следующим:

// src/Blogger/BlogBundle/Controller/PageController.php
public function contactAction(Request $request)
{
    $enquiry = new Enquiry();

    $form = $this->createForm(EnquiryType::class, $enquiry);

    if ($request->isMethod($request::METHOD_POST)) {
      $form->handleRequest($request);

        if ($form->isValid()) {
            // Perform some action, such as sending an email

            // Redirect - This is important to prevent users re-posting
            // the form if they refresh the page
            return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
        }
    }

    return $this->render('BloggerBlogBundle:Page:contact.html.twig', array(
        'form' => $form->createView()
    ));
}



Мы начнём с создания экземпляра сущности Enquiry. Эта сущность представляет данные о contact запросе. Далее мы создадим форму. Определим EnquiryType, который мы создали ранее, и передадим нашему enquiry entity object.
Так как эти действия контроллера будут иметь дело с отображением и обработкой отправленной формы, мы должны проверить метод HTTP. Формы, как правило, передаются через метод POST, и наша форма не будет исключением. Если метод запроса будет POST, вызов submit($request)превратит отправленные данные обратно в элементы нашего $enquiry object. На данный момент объект $enquiry содержит представление о том, что отправил пользователь. Далее мы сделаем проверку, чтобы убедиться, что форма заполнена верно. Так как мы не указали ни одного валидатора на этот момент, форма всегда будет действительна. И наконец мы укажем шаблон для визуализации.

Мы должны импортировать пространства имен в наш контроллер т.к. используем новые классы. Обновите файл контроллера, расположенный в src/Blogger/BlogBundle/Controller/PageController.php

Заявления должны быть размещены под уже имеющимися.

<?php
// src/Blogger/BlogBundle/Controller/PageController.php

namespace Blogger\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Import new namespaces
use Symfony\Component\HttpFoundation\Request;
use Blogger\BlogBundle\Entity\Enquiry;
use Blogger\BlogBundle\Form\EnquiryType;


class PageController extends Controller
{
    //..



Отображение формы


Благодаря шаблонизатору Twig вывод форм очень прост. Twig предоставляет многоуровневую систему для вывода форм, что позволяет выводить форму как одну целую сущность или в виде отдельных ошибок и элементов, в зависимости от уровня настройки которая вам требуется. Чтобы продемонстрировать мощь методов Twig выведем всю форму, следующим фрагментом кода:

<form action="{{ path('BloggerBlogBundle_contact') }}" method="post" >
    {{ form_start(form) }}
    {{ form_widget(form) }}
    {{ form_end(form) }}

    <input type="submit" />
</form>


В то время как, это очень просто для создания прототипов и простых форм, это имеет и свои ограничения, когда необходимы расширенные настройки, что часто бывает с формами.

Для нашей контактной формы, мы выберем золотую середину. Замените код шаблона, расположенный в src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig

{# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}

{% block title %}Contact{% endblock%}

{% block body %}
    <header>
        <h1>Contact symblog</h1>
    </header>

    <p>Want to contact symblog?</p>

  {{ form_start(form, { 'action': path('BloggerBlogBundle_contact'), 'method': 'POST', 'attr': {'class': 'blogger'} }) }}
{{ form_errors(form) }}

{{ form_row(form.name) }}
{{ form_row(form.email) }}
{{ form_row(form.subject) }}
{{ form_row(form.body) }}

{{ form_rest(form) }}

<input type="submit" value="Submit" />

 {% endblock %}


Как вы можете видеть, мы используем 4 новых метода Twig для вывода формы.

Первый метод form_start (вид, переменные) выводит тег начала формы. Этот помощник заботится о выводе метода конфигурации и action в форме. Он также будет включать в себя правильное значение ENCTYPE если форма содержит поля загрузки.

Второй метод form_errors будет выводить ошибки формы в том случае, если проверка не удалась.

Третий метод form_row выводит целые элементы, связанные с каждой областью формы. Это включает в себя какие-либо ошибки в поле, label поля и актуальный элемент поля.

Наконец мы используем метод form_rest. Это безопасный вариант, чтобы использовать метод в конце формы, чтобы сделать какие-либо поля которые вы возможно забыли, в том числе скрытые поля и Symfony2 Form CSRF token.

Заметка

Подделка запроса cross-site (CSRF) объясняется подробно в главе Формы книги Symfony2.


Стилизация формы



Давайте добавим некоторые стили, чтобы улучшить вид формы. Так как эти стили являются специфическими в пределах нашего бандла мы создадим стили в новом файле стилей внутри самого бандла. Создайте новый файл src/Blogger/BlogBundle/Resources/public/css/blog.css и вставьте стили.

.blogger-notice { text-align: center; padding: 10px; background: #DFF2BF; border: 1px solid; color: #4F8A10; margin-bottom: 10px; }
form.blogger { font-size: 16px; }
form.blogger div { clear: left; margin-bottom: 10px; }
form.blogger label { float: left; margin-right: 10px; text-align: right; width: 100px; font-weight: bold; vertical-align: top; padding-top: 10px; }
form.blogger input[type="text"],
form.blogger input[type="email"]
{ width: 500px; line-height: 26px; font-size: 20px; min-height: 26px; }
form.blogger textarea { width: 500px; height: 150px; line-height: 26px; font-size: 20px; }
form.blogger input[type="submit"] { margin-left: 110px; width: 508px; line-height: 26px; font-size: 20px; min-height: 26px; }
form.blogger ul li { color: #ff0000; margin-bottom: 5px; }



Нам нужно, чтобы приложение знало, что мы хотим использовать эту таблицу стилей. Мы могли бы подключить таблицы стилей в шаблон страницы Контакты, но так как другие шаблоны будут также использовать эти стили позже, имеет смысл, импортировать стили в layout Blogger BlogBundle который мы создали в первой части. Откройте BloggerBlogBundle layout src/Blogger/BlogBundle/Resources/views/layout.html.twig и замените содержание следующим:

{# src/Blogger/BlogBundle/Resources/views/layout.html.twig #}
{% extends '::base.html.twig' %}

{% block stylesheets %}
    {{ parent() }}
    <link href="{{ asset('bundles/bloggerblog/css/blog.css') }}" type="text/css" rel="stylesheet" />
{% endblock %}

{% block sidebar %}
    Sidebar content
{% endblock %}



Вы можете видеть, что мы вывели блок стилей для его переопределения, который в свою очередь определен в родительском шаблоне. Важно заметить, что вызывается родительский метод. Это будет подключать файлы стилей, которые определены в app/Resources/base.html.twig, и позволяет добавить наш новый файл стилей. Мы не хотим, переопределять уже существующие таблицы стилей.
Для того, чтобы функция asset правильно поключала файлы, нам нужно скопировать или связать ресурсы бандла в папке web нашего приложения. Это может быть сделано следующей командой в консоли:

php app/console assets:install web --symlink


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



Давайте изменим маршрут, расположенный src/Blogger/BlogBundle/Resources/config/routing.yml для обработки POST запросов.


# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_contact:
    path:  /contact
    defaults: { _controller: "BloggerBlogBundle:Page:contact" }
    requirements:
        methods:  GET|POST



Заметка

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


Валидаторы


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

Давайте начнем с обновления сущности Enquiry, расположенной в src/Blogger/BlogBundle/Entity/Enquiry.php укажем несколько валидаторов. Убедитесь, что вы добавили 4 новых заявления в верхней части файла.

<?php

// src/Blogger/BlogBundle/Entity/Enquiry.php

namespace Blogger\BlogBundle\Entity;

use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Length;


class Enquiry
{

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank());
        $metadata->addPropertyConstraint('email', new Email());
        $metadata->addPropertyConstraint('subject',  new Length(array(
            'max'        => 50

        )));
        $metadata->addPropertyConstraint('body', new Length(array(
            'min'        => 50
        )));
    }
 //..



Чтобы определить валидаторы, мы должны реализовать статический метод loadValidatorMetadata. Он даст нам объект ClassMetadata. Мы можем использовать этот объект, чтобы установить ограничения на элементы наших сущностей.
Первое заявление NotBlank применяется к элементу name. NotBlank валидатор проверяет не является ли поле пустым.
Далее мы проверяем правильно ли пользователь ввёл свой e-mail. Служба Symfony2 предоставляет валидатор который проверяет правильность заполнения поля e-mail включая проверку домена.
Мы хотим, чтобы поле темы не было пустым и содержало не более 50 символов, а сообщение не менее 50 символов.
Вы можете применить столько валидаторов к одному полю сколько вам необходимо.

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

Теперь, при отправке формы, ваши данные будут проходить валидацию. Попробуйте ввести неправильный адрес электронной почты. Вы должны увидеть сообщение об ошибке, информирующее о том, что адрес электронной почты является недействительным. Каждый валидатор выводит сообщение по умолчанию, которое может быть переопределено, если требуется. Например, чтобы изменить сообщения e-mail валидатора вы можете сделать следующее:

$metadata->addPropertyConstraint('email', new Email(array(
    'message' => 'symblog does not like invalid emails. Give me a real one!'
)));



Заметка

Если вы используете браузер, который поддерживает HTML5, вам будут выведены сообщения HTML5 определенных ограничений. Это проверка на стороне клиента и Symfony2 установит подходящие ограничения HTML5 на основе метаданных Entity. Вы можете увидеть это на элементе email. Отображение HTML

<input type="email" id="contact_email" name="contact[email]" required="required">


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



Отправка Email


В то время как наша форма контактов позволяет пользователям отправлять запросы, ничего на самом деле пока не происходит. Давайте обновим контроллер, чтобы отправить письмо веб-мастеру блога. Symfony2 поставляется в комплекте с библиотекой SwiftMailer для отправки электронной почты. Swift Mailer является очень мощной библиотекой, мы только лишь прикоснёмся к тому, что эта библиотека может выполнять.

Конфигурация настроек SwiftMailer

Swift Mailer уже настроен из коробки работать в Symfony2, однако нам нужно настроить некоторые параметры, касающиеся способов отправки и полномочий. Откройте файл параметров, расположенный в app/config/parameters.yml и найдите настройки с префиксом mailer_.

mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: null
mailer_password: null


Swift Mailer предоставляет ряд методов для отправки электронной почты, в том числе с использованием сервера SMTP, используя ‘местную' установку Sendmail, или даже с помощью учетной записи Gmail. Для простоты мы будем использовать учетную запись Gmail. Обновите параметры, подставив свой логин и пароль.

mailer_transport: gmail
mailer_encryption: ssl
mailer_auth_mode: login
mailer_host: smtp.gmail.com
mailer_user: ваш_логин
mailer_password: ваш_пароль



Важно !


Будьте осторожны, если вы используете систему контроля версий (VCS) как Git для вашего проекта, особенно если ваше хранилище общедоступно. Вы должны убедиться, что файл приложения
app/config/parameters.yml
добавлен в список игнорируемых
вашего VCS.



Контроллер

Обновите Page контроллер расположенный src/Blogger/BlogBundle/Controller/PageController.php скопировав в него следующий код:

if ($form->isValid()) {
    $message = \Swift_Message::newInstance()
        ->setSubject('Contact enquiry from symblog')
        ->setFrom('enquiries@symblog.co.uk')
        ->setTo('email@email.com')
        ->setBody($this->renderView('BloggerBlogBundle:Page:contactEmail.txt.twig', array('enquiry' => $enquiry)));


    $this->get('mailer')->send($message);

    $this->get('session')->getFlashBag()->add('blogger-notice', 'Your contact enquiry was successfully sent. Thank you!');

    // Redirect - This is important to prevent users re-posting
    // the form if they refresh the page
    return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));

}



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

Заметка

Так как библиотека Swift Mailer не использует пространства имен, мы должны поставить префикс перед классом Swift Mailer \. Это говорит PHP, вернуться обратно в глобальное пространство. Вам нужно будет добавить префикс всем классам и функциям, которые не имеют пространство имен с \. Если вы не разместите этот префикс перед классом Swift_Message PHP будет виден для класса в текущем пространстве имен, которое в этом примере является Blogger\BlogBundle\Controller, в результате чего будет выведена ошибка.


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

Для отображения flash сообщения нам необходимо обновить шаблон контактов, расположенный src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig обновите содержание шаблона:
//..
<header>
    <h1>Contact symblog</h1>
</header>

{% for flashMessage in app.session.flashbag.get('blogger-notice') %}
    <div class="blogger-notice">
        {{ flashMessage }}
    </div>
{% endfor %}

<p>Want to contact symblog?</p>
//..



Этот код проверяет, является ли flash сообщение с идентификатором blogger-notice установленным и выведено.

Регистрация email’а веб-мастера


Symfony2 предоставляет систему конфигурации, которую мы можем использовать, чтобы определить наши собственные настройки. Мы будем использовать эту систему для установки электронной почты веб-мастера, а не жесткого кодирования адреса в контроллере выше. Таким образом, мы можем легко повторно использовать это значение в других местах без дублирования кода. Кроме того, когда ваш блог вызывает столько трафика которого стало слишком много для вас, вы можете легко обновить адрес электронной почты, чтобы передать письма вашему помощнику. Создайте новый файл src/Blogger/BlogBundle/Resources/config/config.yml и вставьте следующее:

parameters:
    # Blogger contact email address
    blogger_blog.emails.contact_email: contact@email.com


При определении параметров хорошей практикой является разделение имен параметров на количество компонентов. Первая часть должна быть в нижнем регистре и использовать нижнее подчеркивание для разделения слов. В нашем примере мы превратили бандл BloggerBlogBundle в blogger_blog… Оставшаяся часть имени параметра может содержать любое количество частей разделенных. (Точкой). Это позволяет логически группировать параметры.
Для того, чтобы приложение Symfony2 использовало новые параметры, мы должны импортировать конфигурацию в главный файл конфигурации приложения, app/config/config.yml для этого, добавьте следующее:

# app/config/config.yml
imports:
    # .. existing import here
    - { resource: "@BloggerBlogBundle/Resources/config/config.yml"}


Путь импорта – это физическое расположение файла на диске.

Наконец давайте обновим функцию contactAction для использования параметра.

// src/Blogger/BlogBundle/Controller/PageController.php

public function contactAction(Request $request)
{
    $enquiry = new Enquiry();

        $form = $this->createForm(EnquiryType::class, $enquiry);

    if ($request->isMethod($request::METHOD_POST)) {
        $form->handleRequest($request);
        if ($form->isValid()) {
            $message = \Swift_Message::newInstance()
                ->setSubject('Contact enquiry from symblog')
                ->setFrom('enquiries@symblog.co.uk')
                ->setTo($this->container->getParameter('blogger_blog.emails.contact_email'))
                ->setBody($this->renderView('BloggerBlogBundle:Page:contactEmail.txt.twig', array('enquiry' => $enquiry)));


            $this->get('mailer')->send($message);

            $this->get('session')->getFlashBag()->add('blogger-notice', 'Your contact enquiry was successfully sent. Thank you!');

            // Redirect - This is important to prevent users re-posting
            // the form if they refresh the page
            return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));

        }

    }

    return $this->render('BloggerBlogBundle:Page:contact.html.twig', array(
        'form' => $form->createView()
    ));
}




Совет

Так как конфигурационный файл импортируется в верхнюю часть файла конфигурации приложения мы можем легко переопределить любой из импортируемых параметров в приложении. Например, добавив следующую строку в нижнюю часть app/config/config.yml будет переопределено значение параметра.

# app/config/config.yml
parameters:
    # Blogger contact email address
    blogger_blog.emails.contact_email: assistant@email.com



Создание шаблона e-mail


Тело нашего email, выводит шаблон. Создайте этот шаблон в src/Blogger/BlogBundle/Resources/views/Page/contactEmail.txt.twig
и добавьте следующее:
{# src/Blogger/BlogBundle/Resources/views/Page/contactEmail.txt.twig #}
A contact enquiry was made by {{ enquiry.name }} at {{ "now" | date("Y-m-d H:i") }}.

Reply-To: {{ enquiry.email }}
Subject: {{ enquiry.subject }}
Body:
{{ enquiry.body }}



Вы может так же заметили, что расширение этого шаблона отличается от других шаблонов, которые мы создали. Он использует расширение .txt.twig. Первой частью расширения, .txt определяется формат файла для генерации. Общие форматы включают, .txt, .html, .css, .js, XML и .json. В последней части расширения определяет, какой движок шаблона использовать, в данном случае Twig. Расширение .php использовало бы PHP для отображения шаблона.
Теперь, когда Вы отправили запрос письмо будет отправлено на адрес, указанный в параметре blogger_blog.emails.contact_email.

Совет

Symfony2 позволяет настроить поведение библиотеки SwiftMailer при работе в различных средах Symfony2. Мы уже видим это в использовании для тестовой среды. По умолчанию, Symfony 2 настраивает SwiftMailer не посылать электронную почту, когда работает в тестовой среде. Это устанавливается в конфигурационном файле app/config/config_test.yml

swiftmailer:
    disable_delivery: true



Это может быть полезно, чтобы продублировать эту функциональность для среды Dev. В конце концов, вы наверняка не хотите, случайно отправить письмо по неправильному адресу при разработке. Для достижения этой цели, добавьте вышеуказанную конфигурацию в файл конфигурации Dev, расположенного app/config/config_dev.yml


Вы будете удивлены, как вы можете проверить, что письма были отправлены. Symfony2 имеет решение для этого с помощью панели инструментов разработчика. Когда письмо будет отправлено значок-уведомление электронной почты появится в панели инструментов, который имеет всю информацию о письме.
Если вы выполняете перенаправление после отправки электронной почты, как мы делаем для контактной формы, вам нужно будет установить intercept_redirects настройки app/config/config_dev.yml в значение true для того, чтобы увидеть уведомление электронной почты на панели инструментов.



Мы могли бы настроить SwiftMailer для отправки всех писем на определенный адрес электронной почты в среде Dev, поместив следующий параметр в конфигурационном файле Dev, расположенного app/config/config_dev.yml

swiftmailer:
    delivery_address: development@symblog.dev


Вывод


Мы продемонстрировали концепции, для создания одной из самых фундаментальных частей любого веб-сайта: формы.
Далее мы рассмотрим большую часть этого руководства, Модель. Расскажем о Doctrine 2 и используем его для определения blog Model. А также исследуем концепцию Data fixtures.

Источники и вспомогательные материалы:

https://symfony.com/
http://tutorial.symblog.co.uk/
http://twig.sensiolabs.org/
http://www.doctrine-project.org/
https://getcomposer.org/

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



Часть 1 — Конфигурация Symfony2 и шаблонов
Часть 3 — Doctrine 2 и Фикстуры данных
Часть 4 — Модель комментариев, Репозиторий и Миграции Doctrine 2
Часть 5 — Twig расширения, Боковая панель(sidebar) и Assetic
Часть 6 — Модульное и Функциональное тестирование


Также, если Вам понравилось руководство вы можете поставить звезду репозиторию проекта или подписаться. Спасибо.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Пожалуйста, оцените качество руководства

Поделиться публикацией

Комментарии 56

    +2
    Хорошо бы указать, что предпочтительнее создавать формы-классы, создание форм в контроллере — не лучшая практика. Формы-классы проще в тестировании и переиспользуемы. Об этом кстати описано в официальной документации.
      0
      И на них можно вешать события, например, для для изменения данных перед обработкой или удаления лишних полей. symfony.com/doc/current/components/form/form_events.html
        0
        Не могли бы вы привести ссылку или показать пример? В документации, даже в разделе о формах в «best practices», формы создаются как в статье:
        public function newAction(Request $request)
        {
            $post = new Post();
            $form = $this->createForm(PostType::class, $post);
            // ...
        }

        код взят с http://symfony.com/doc/current/best_practices/forms.html
          0
          http://symfony.com/doc/current/book/forms.html#building-the-form читайте приписку
            0
            Так ведь в данном переводе форма так и создается, через формы-классы, или я не прав? Я совсем недавно начал разбираться с symfony, так что возможно я что-то упускаю
              0
              This example shows you how to build your form directly in the controller. Later, in the «Creating Form Classes» section, you'll learn how to build your form in a standalone class,
              which is recommended as your form becomes reusable.
                0
                извиняюсь. не заметил что пост обновили. в начальной версии поста использовался билдер в контроллере.
              0
              (PostType::class, $post);

              Вся форма на самом деле задается внутри PostType.

                0
                Да, я уже разобрался, просто я читал эту статью в той версии, в которой она сейчас и прочитав комментарий maximkou подумал, что есть более предпочтительный способ, чем тот который описан в статье.
            +4
            Несколько небольших изменений
            Конструкцию
            $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
            

            лучше заменить на
            $this->redirectToRoute('BloggerBlogBundle_contact');
            

            , а проверку
            $request->getMethod() == 'POST'

            лучше заменить на
            $request->isMethod($request::METHOD_POST)
            
              –7
              Кто тоже считает, что Симфони слишком сложный, вам сюда:
              http://blog.kpitv.net/article/frameworks-1/

              Кто не считает, можете тоже сходит.
              Статья изменит вашу точку зрения на фреймворки.
                +1
                Не изменила. Фреймфорк это инструмент, как хочешь, так и пользуй. Никто не запрещает его изменять. И никто не запрещает писать свой инструмент. Главное, чтоб нравилось.
                  –4
                  А толку с инструмента, который не рабочий?
                  Вы покупаете молоток в магазине, а потом дорабатываете его и половину выбрасываете? :)
                    +2
                    Рабочий.

                    Беря молоток в руки, не означает, что гвоздь сам забьется. Вы же хотите, от фреймворка, функционал CMS, но фреймворки не об этом.
                      –2
                      Фреймворк — это отдельно купить брусок и отдельно держание? :)
                      О да, это сильно :)
                        +1
                        Инструментом либо умеешь пользоваться, либо пилишь молотком.
                  +2
                  Нас е**т, а мы крепчаем
                  — это про вас.
                  Вас минусуют за пиар своей статьи, а вы все равно вставляете ссылку на нее в каждом посте, который как-то связан с веб-разработкой.
                    –3
                    Минусуют не за пиар статьи.
                    А из-за того, что у людей когнитивный диссонанс, они не могут понять, как можно обойтись без фреймворков.
                    Минусуют и комменты без ссылок.
                    А ссылку я вставляю только в постах, связанных с фремворками.
                      +3
                      Лично мне без разницы, используете вы фреймворки или нет. Ваше дело.

                      Задевает постоянный постинг ссылки на эту статью. Такое ощущение, что вы навязываете свою идеологию, причем выходит не убедительно. Или я ошибаюсь?
                        0
                        Лично мне тоже без разницы, использует ли кто-то фреймворки.
                        Те, кто их уже использует, вряд ли перестянет.
                        Просто фреймворки приподносятся как некая панацея, но это не так. Там говнокода тоже тонны.
                        Хотя как пристанище говнокодеров (хотя там есть и нормальные программисты) фреймворки выполняют свою роль отлично.

                        Я против пропаганды фреймворков среди неокрепших умов.
                        Я навязываю идеологию KISS. :)
                        А что именно неубедительно? :)
                          0
                          Фреймворки не панацея, согласен. И говнокод порой встречается.

                          Но реалии бизнеса таковы, что, как правило:
                          1. Стартовать нужно в сжатые сроки, а иногда даже вчера. Всем пофиг что вы уже полгода пишете крутое ядро. Бизнесу нужен результат.
                          2. Нужны некие стандарты и документация, дабы любой разработчик быстро сориентировался в проекте

                          Это как минимум. Со всем этим фреймворки справляются неплохо, при этом позволяют поддерживать код в поддерживаемом состоянии.

                          Раз уж вы заговорили о принципе KISS, то одним из его важных составляющих является сохранение методов/классов маленькими и простыми. Этого я не увидел в коде, который показал нам MetaDone

                          А что именно неубедительно? :)

                          Неубедительны приводимые вами аргументы. Большая часть из них очень субъективны, некоторые просто высосаны из пальца.

                          Например:
                          При выпуске новых версий как правило отсутствует обратная совместимость. Программисты на фреймворках никогда не останутся без работы.

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

                          Некоторые фреймворки ориентированы на аннотации (комментарии) — это тихий ужас.

                          А мне нравятся аннотации. Очень удобно, например, описать роут рядом с обработчиком(экшеном). Субъективно? Да.
                            –2
                            >Стартовать нужно в сжатые сроки, а иногда даже вчера.

                            Зачем брать фреймворк и мудохаться с ним, если можно взять CMS?

                            >Всем пофиг что вы уже полгода пишете крутое ядро.

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

                            >Бизнесу нужен результат.

                            Бизнесом, как правило, управляют те еще стратеги. :)

                            >Нужны некие стандарты и документация, дабы любой разработчик быстро сориентировался в проекте

                            Мои 50 КБ можно изучить за день :)
                            Стандарты должны быть логичными. Если стандартов слишком много и они не логичны — на них всем начхать.

                            KISS.
                            Это кусок контроллера.
                            Я не вижу смысла разбивать функцию на мелкие функции, если не будет повторного использования.
                            Зачем плодить абстрации?

                            >семантическое версионирование

                            Какая разница, какое версионирование?
                            Вон Битриксы все совместимы.

                            >А мне нравятся аннотации.

                            Аннотации могут нравиться, но это путанье мух с котлетами по факту. )
                              0
                              Зачем брать фреймворк и мудохаться с ним, если можно взять CMS?

                              А cms же у нас конфетка, точно.

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

                              А пишете вы его дома в свободное время?

                              Мои 50 КБ можно изучить за день

                              Ну действительно, зачем документация нужна.

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

                              Например, чтобы не читать весь код, а увидеть суть. Тесты написать проще, не? Никто вас не просит кучу абстракций накладывать. Не нужно в крайности бросаться. Использовать абстракции нужно, но к месту и умеренно.

                              Вон Битриксы все совместимы.

                              Вон Вася спился. Давай и я тоже сопьюсь.

                              Аннотации могут нравиться, но это путанье мух с котлетами по факту. )

                              Вы считаете что аннотации — ужас. Я считаю, что это удобно. Получается, что ваше мнение субъективно, верно? Субъективно — значит применимо к одному субъекту.
                                –1
                                >А пишете вы его дома в свободное время?

                                А Вы сапожник без сапог? :)

                                >Ну действительно, зачем документация нужна.

                                А я и не говорю, что не нужна :)

                                >чтобы не читать весь код, а увидеть суть

                                Большинство ИДЕ имеет сворачивание кода.

                                >Вон Вася спился. Давай и я тоже сопьюсь.

                                Я ж приводил позитивный пример.

                                >Субъективно

                                При чем тут субъективно — не субъективно? Это мешание в кучу мух и котлет.
                                0
                                А где ваши 50 Кб можно посмотреть?
                                  –4
                                  Пока нигде потому что:
                                  1. Это пока ноу-хау.
                                  2. Я не хочу распространять код, если он будет труднообновляем. Нужно будет завернуть все в композитор, или как. У меня проблем с обновлениями моих сайтов пока нет, поэтому руки не доходят. :)
                                  3. Я бы еще хотел как-то заработать на этом коде. :) Скорее всего не прямо. Возможно что-то вроде расширенной версии, как у нгинкса. :) В композиторе можно использовать сторонние репозитории с ключем доступа?
                                  4. Как решают проблему конфликта классов сущностей другие? То есть какое-то расширение поставляет с собой какие-то сущности. Как обойти конфликты? Пользовательские сущности выносить в неймспейсы?
                                  5. Перед выпуском в паблик стоило бы подчистить немного легаси код, там пару методов ядра.
                                  6. Нужно написать документацию.
                                  7. Я не знаю, как систему встретят, будут ли пользоваться. Если не будут, то смысла как бы и нет выкладывать. :)
                          +2
                          Обойтись без фреймворков — это каждый раз собирать молоток для того, чтобы забить гвоздь? Причем молоток не проверенный годами и сотнями забитых гвоздей из дерева и металла, а из ДСП и пластика, который вот-вот сломается, возможно при первом же ударе по гвоздю :)
                            0
                            1. Меня уровень проверки качества фреймворков не устроил.
                            Они как китайские молотки, как бренды-пустышки (слышал, у Бугатти днище гниет за 2 года :) ). :)
                            Почему берут фрейворки? Чтобы быстрее (якобы еще дешевле) состряпать продукт.
                            В результате выходит черти что.
                            Использовать фреймворк — это использовать кувалду, где нужен средний молоток.
                            2. Каждый раз собирать молоток не нужно при грамотном подходе. Можно, конечно, мудохаться и в самописи, каждый раз переизобретая ранее собой же изобретенный велосипед, но это тупо.
                              0
                              Какой уровень проверки вы считаете приемлемым? Если это проект на Гитхабе, то его уровень можно посмотреть по количеству открытых/закрытых задач, покрытию тестами и отклику сообщества по тем или иным задачам и вопросам. Или вы что-то другое имеете в виду?
                                –2
                                Фреймворки слишком универсальны.
                                  +1
                                  На то они и фреймворки. Некоторые, как Symfony, можно разобрать на отдельные компоненты и взять только то, что нужно. И всё.
                            +3
                            А из-за того, что у людей когнитивный диссонанс, они не могут понять, как можно обойтись без фреймворков.

                            Мы как-то дискутировали с вами, и выяснилось что у вас просто далеко не те проекты, где нужны фреймворки уровня симфони. "бложики" на симфони писать как-то сильно оверхэд.


                            А вот опыта с проектами того уровня, где фреймворки спасают у вас попросту видимо нет. Так что ваше мнение не заслуживает внимания.

                              0
                              А для каких же проектов стоит использовать фреймворки и почему?
                              Какие у вас есть такие проекты?
                                +2

                                Давайте я просто расскажу как у меня происходят отношения с фреймворками, библиотеками и т.д. на примере сферического в вакууме проекта, а потом обсудим все же что именно вам не нравится (в конце):


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


                                Бизнес-аналитики накидывают мне юзкейсы/юзерстори (или менеджеры, или я сам их накидываю себе в виду фичаспек по результатам обсуждения), из которых формируется представление о том как что делается. Например краиугольным камнем нашего продукта являются платежи.


                                Что я делаю, я пишу на PHP (никаких фреймворков пока) сущности, примерно как у нас вышло при декомпозиции задачи. Причем только в рамках той фичи которую я сейчас делаю. Частенько я делаю это дело по TDD. Если мне нужна какая-то функциональность вроде "послать email со счетом" я не бросаю все и пишу очередной мэйлер, а просто делаю интерфейс штуки, которая будет для меня это все делать.


                                В результате через пару-тройку часов у меня есть вся бизнес логика этой фичи. Как только она готова, и я покрыл тестами все интересующие меня моменты, можно браться за инфраструктуру. Прикручивать базы данных (доктрина, она полностью абстрагирует меня от слоя хранения данных, очень быстро подобные штуки пилить), писать контроллеры для HTTP API (симфони, по сути только то что нужно для http, никаких форм, только валидация запросов + реквесты/респоны, обработка ошибок), реализую сервисы для отправки нотификаций (какие-то библиотеки поставленные через composer + реализация интерфейса который я написал как заглушку для тестов).


                                Нужно прикрутить авторизацию? пара десятков минут и у меня уже прикручена авторизация через JWT. Нужно сделать запись всех запросов — не проблема, ставим бандл, 15 минут и готово. Нужно гибко управлять правами — symfony/security предоставляет механизм воутеров, с которыми я могу описать даже ооочень сложную логику разграничения прав на раз-два.


                                Любая стандартная задача — меньше часа с учетом чтения доки и "сходить за кофе". Если внезапно приходит хотелка от клиента "ну мы хотим сделать меганестандартную аутентификацию через 10 разных сервисов" — оке, просто делаю свою реализацию аутентификатора реализующего стандартный интерфейс, предоставляемый мне symfony. Он достаточно гибкий что бы сделать практически все что угодно. А даже если внезапно по каким-то причинам его будет не хватать — не вопрос, делаем полностью свою систему аутентификации сверху нашего приложения, симфони предоставляет мне и такую возможность.


                                Если мы бложики пишем — симфони скорости разработки нам не добавит в сравнении с фреймворками вроде laravel или просто plain php + composer пакеты. А вот если мы интернет магазин пилим — то существенно ускоряется как написание MVP проекта, так и сопровождение значительно дешевеет.


                                НО!


                                Все это хорошо работает потому что я с Symfony и Doctrine работаю уже почти 5 лет, знаю их на очень хорошем уровне изнутри. Так же я стараюсь писать код так, что бы он небыл слишком сильно завязан на фреймворк (инверсия зависимости и все такое). Это происходит естественным образом поскольку я начинаю проектировать систему с бизнес логики а не контроллеров.


                                А подавляющая масса новичков начинает делать дела с фреймворками даже не прочитав документацию к фреймворку. А ведь если все делать методом тыка — то эффективности фреймворки при разработке не добавляют. То есть что бы фреймворки приносили пользу, их нужно знать хотя бы на базовом уровне. В случае Symfony нужно знать хотя бы те компоненты, которые вы используете повседневно (в моем случае это 5-6 компонентов на самом деле из десятков). То есть нам нужно инвестировать свое время в изучение инструмента что бы его использование начиинало окупаться.


                                Если без этого… разницы как бы нет, с фреймворком или нет — скорее всего получится неподдерживаемый трэшачек.

                          0
                          http://govnokod.ru/19878
                          не изменит
                          +1
                          Не первый раз вижу ссылку на эту статью. Более того, прочитал несколько раз и попытался осмыслить ее с нейтральной точки зрения. В этом свете возник вопрос — можно ли увидеть код (полностью или часть его) Вашего «ядра», о котором Вы упоминали? Ибо у меня складывается впечатление, что Ваше «ядро» не что иное, как еще один фреймворк.
                            0
                            Я его не называю таким замараным словом, как фреймворк.
                            И оно легко для понимания, в отличии от фрейморков.
                            Содержит всего 50Кб.
                            У меня используются нативные функции языка, а не так, что каждый фреймворк по сути является новым языком.
                            А пишущие на фреймворках не умеют самостоятельно строить архитектуру.
                            Также не мое ядро дергает пользовательский код, а пользовательский код дергает ядро.
                              0
                              Это замечательно. А можно все-таки пример увидеть, не часть кода, вырванного из контекста, а целостную картину (git репозитарий, листинг на сайте или др.)?
                                +1
                                1. Код пока ноу-хау.
                                2. Там ничего как бы особенного нет:
                                автолоадинг
                                события
                                работа с языками
                                кеширование

                                Просто сделано ради решения задач самым простым способом, а не чрезмерно академически.
                                Ядро в чем-то божественный объект. Но это оправдано, как и в случае с jQuery, нету лишних сущностей.
                                Фреймворки привносят очень много своих сущностей в разработку.

                                Я не против фреймворков ради того, чтобы быть против них.
                                Я против их недостатков.
                                Часто чтобы решить тривиальную задачу приходится долго мудохаться с фреймворком и его документацией.
                                  +1
                                  Ясно-понятно, спасибо за комментарий
                                    0
                                    Ждём статей на Хабре!
                                  +2

                                  Знаете, у вас в вашем блоге (в разделе IT) много чего занятного, не только по теме данной статьи. Там можно долго обсуждать и комментировать многие темы:


                                  • Почему я не использую тесты кода
                                  • Методологии разработки говно
                                  • ООП говно
                                  • Почему я не использую Twitter Bootstrap

                                  Не смотря на то, что с некоторыми тезисами (но им не хватает должного раскрытия) я лично как-бы согласен, но в принципе наблюдается сумбурность вообще по многим темам в целом и по фреймворкам в частности:


                                  • бОльшая часть негатива адресована Yii. Видимо, потому что там наибольший опыт. Но Yii (особенно 1) — не самый лучший пример фреймворка, да простят меня разработчики, которые используют его.
                                  • вы часто делаете выводы из частного на общее. Например, пример плохого кода из приложения, которое написано с помощью какого-то фреймворка — не сам код фреймворка, а именно приложения! — для вас является показателем качества первого (фреймворка)

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


                                  вот немногое


                                  • методологию
                                  • тестирование
                                  • метрики кода
                                  • знание инструментов
                                  • возможности языка
                                  • алгоритмы
                                  • и т.д.

                                  Если по каким-то пунктах вы уходите так сказать в сторону и у вас появилось раздражение или плохие результаты (невозможность применять инструмент как хочется я также отношу к плохим результатам), это не значит что что-то из этого говно. Это значит, что где-то в применении подхода появился изъян. Важно, что тут речь о практике, а не о теории. И не надо всё месить в кучу. Надо "отдебажить" подход и посмотреть что из набора у вас работает не так как вы хотели и почему.


                                  Может вам ЯП надо поменять или какой-то инструмент. Но в любом случае это напрямую зависит от задачи, которую вы решаете в данный момент. Инструменты разные же для разных целей. Если вам для склеивания фарворовой кружки не полошел молоток или скальпель — это необязательно потому что они — говно. Просто для склеивания надо использовать другое!


                                  А вообще я согласен с мыслью, что фреймворки не надо использовать, но в том смысле, что так или иначе он у вас есть (50 КБ своей гордости), просто надо выбирать лучший, а лучший — это который помогает, а не мешает. В идеале вы его со временем просто не будете замечать.

                                    0
                                    >но им не хватает должного раскрытия
                                    >наблюдается сумбурность вообще по многим темам

                                    Я часто пишу «статьи» не целенаправленно, а в результате участия в холиварах :)
                                    Статьи постепенно дополняются.

                                    >адресована Yii. Видимо, потому что там наибольший опыт

                                    На всех работах с фреймворками использовался именно он.
                                    А в статьях он потому, что я его использую на работе сейчас

                                    >часто делаете выводы из частного на общее

                                    Иногда это примеры :)

                                    >для вас является показателем качества первого

                                    Ну. например, возможность sql-инъекций — это к фреймворку, ибо говорится, что он от них спасает. :)

                                    >это не значит что что-то из этого говно. Это значит, что где-то в применении подхода появился изъян.

                                    Фреймворки очень сложны и это плата за их универсальность.
                                    Мне такая универсальность не нужна.
                                    А местами не логичны.

                                    >Может вам ЯП надо поменять или какой-то инструмент.

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

                                    >так или иначе он у вас есть

                                    Рад, что поняли :)
                              • НЛО прилетело и опубликовало эту надпись здесь
                                  0
                                  >MVC это архитектура
                                  Я бы сказал, это здравый смысл.

                                  Жирные модели — это все равно, что у курятника будет 10-метровый фундамент… :)

                                  >Делается наследование от класса
                                  Наследование увеличивает сложность, не универсально.

                                  >Думаю это основная причина вашей неприязни фреймворков.
                                  Да :)

                                  >В случае с Yii ни когда не испытывал проблем с документацией.
                                  Она написана как будто для идиотов. Вот именно в Yii. Для создания хоумпаджей. А иногда просто phpdoc

                                  >А страницы не авторизованных пользователей грузятся 5-1мс. Грамотное использование имеющихся механизмов кеширования.
                                  Закешировать страницу целиком — это не совсем грамотно. Да и в 1-5мс я не верю как-то :)

                                  >Nginx прекрасно с этим справляется.
                                  Ну да, нгинкс веб-сервер :)

                                  >Статичная страница на Yii создается 10 строчками кода.
                                  А хедер/футер у такой странички будет?

                                  >По вашему ORM не нужен?
                                  1. Я писал не об ОРМ, а о конструкторах запросов, вроде andWhere/orWhere
                                  2. Но да, я против ОРМ, это лишняя абстракция.

                                  >В роутинге прописывается все достаточно легко. Дальше зависит от ваших рук и головы.
                                  Удалил этот пункт :)

                                  >Точно так же нужные фичи реализуются во фреймворке
                                  Во фреймворках желательно же реализовывать фичи на АПИ самого фреймворка. А часто это усложнено, так как АПИ не предусматривает такого.

                                  >По сути CMS, они есть, см. github.
                                  Интерфес добавления пунктов меню должен быть одинаков.
                                  Каждая CMS на разном фреймворке скорее всего реализует это по своему.

                                  >Виджеты есть.
                                  Я имел в виду программный интерфейс.

                                  >Между 5 и 7й версией PHP тоже не идеальная совместимость.
                                  У меня было только 2 проблемы с 5.2 на 7:
                                  удаленные функции split и mysql_

                                  >Например внутри Yii 1.x с совместимостью все хорошо.
                                  А хотелось бы и 2 с 1. :)
                                  Как в Битриксе.
                                  Да, это сложно.

                                  >Yii::app()->clientScript->registerCssFile(Yii::app()->request->baseUrl. '/css/style.css?'.md5_file(Yii::app()->basePath.'/../css/style.css'));
                                  У меня на работе аутсорсеры, от которых достался код, просто прописали
                                  />

                                  md5 файла тяжелая ф-я, лучше filemtime()…

                                  >Безопасность и гибкость.
                                  Откуда безопасность?
                                  А гибкость зачастую не нужна.
                                  Понятней обычные массивы GPCS.
                                    0
                                    MVC это архитектура

                                    Model2 это архитектура (то что используется в Yii по сути), MVC это прием для уменьшения связанности приложения и GUI. Причем не используется активно уже лет 20 и является самой бесполезной аббривиатурой так как люди вкладывают туда самый разный смысл.


                                    Symfony же (что бы вернуться к текущему посту) это request/response фреймворк и его хоть и можно подогнать под Model2 но нет смысла.


                                    Делается наследование от класса, где реализуете алгоритм нужных вам настроек.

                                    композиция лучше наследования, но ладно


                                    По вашему ORM не нужен?

                                    справедливости ради — далеко не всегда он нужен.


                                    Например внутри Yii 1.x с совместимостью все хорошо.

                                    у симфони еще лучше)

                                  0
                                  Тут похоже опечатка, рендерится некорректно

                                  <form action="{{ path('BloggerBlogBundle_contact') }}" method="post" {{ form_start(form, { 'attr': {'class': 'blogger'} }) }}
                                  


                                  Нужно просто

                                  {{ form_start(form, { 'action': path('BloggerBlogBundle_contact'), 'method': 'POST', 'attr': {'class': 'blogger'} }) }}
                                  
                                    0
                                    спасибо, исправил
                                      +1

                                      method у форм по умолчанию POST и поэтому его явно указывать не нужно.


                                      Ну и обработку формы можно оптимизировать


                                      $form = $this
                                          ->createForm(EnquiryType::class, $enquiry)
                                          ->handleRequest($request);
                                      
                                      if ($form->isValid()) {
                                          // отправка письма
                                      }

                                      Нет необходимости проверять запрос на POST, это сделает автоматически компонент форм

                                        +1

                                        по оформлению форм в шаблоне, правильней всего так:


                                        {{ form_start(form, {action: path('BloggerBlogBundle_contact'), attr: {class: 'blogger'}}) }}
                                        {{ form_widget(form) }}
                                        <button type="submit">Submit</button>
                                        {{ form_end(form) }}
                                      +4
                                      Несколько замечаний:
                                      • Symfony best practices рекомендует использовать аннотации для описания роутов.
                                      • Валидаторы сущности лучше тоже делать через аннотации. По крайней мере это наглядней.
                                      • Хоть это и не описано в best practices, но если вы протестируете свой проект в SensioLabsInsight, то выясните что все формы должны находится в директории src/Blogger/BlogBundle/Form/Type/.
                                      • Параметры приложения принято описывать в файле parameters.yml, а не config.yml.
                                      • Конфиги бандла принято подглючать через DI extension, а не через app/config/config.yml.

                                      Symfony2 автозагрузчик будет искать необходимые файлы в директории src


                                      В Symfony нет автозагрузчика. Symfony использует для автозагрузки Composer.
                                      Он использует расширение .txt.twig. Первой частью расширения, .txt определяется формат файла для генерации. Общие форматы включают, .txt, .html, .css, .js, XML и .json. В последней части расширения определяет, какой движок шаблона использовать, в данном случае Twig. Расширение .php использовало бы PHP для отображения шаблона.


                                      Расширение .html.twig это только рекомендации к наименованию расширения. Расширение файлов ни как не влияет на работу шаблонизаторов. Можно указать любое расширение, хоть .foo.bar.

                                      Вместо
                                      $this->container->getParameter('blogger_blog.emails.contact_email')


                                      можно использовать getParameter
                                      $this->getParameter('blogger_blog.emails.contact_email')


                                      Вместо
                                      $this->get('session')->getFlashBag()->add('blogger-notice', 'Your contact enquiry was successfully sent. Thank you!');


                                      можно использовать addFlash
                                      $this->addFlash('blogger-notice', 'Your contact enquiry was successfully sent. Thank you!');


                                      Несколько мелких замечаний по оформлению:
                                      • В сущностях рекомендуется описывать реальные типы, а не писать везде mixed.
                                      • В сущностях рекомендуется указывать значение по умолчанию. Например email всегда должен быть строкой и не когда не должен становится null-ом.
                                      • В setter-ах рекомендуется возвращать ссылку на текущий объект $this чтобы можно было использовать цепочки вызовов.
                                      • В классе формы рекомендуется использовать цепочку вызовов для конфигурирования формы.
                                      • В форме метод configureOptions не обязательный и если он пустой, то лучше его вообще не указывать.


                                      PS: В целом статья хорошая. Спасибо за проделанную работу. Хотя лучше писать качественный код чтобы новички не перенимали плохое.
                                      PSS: Не сочтите за рекламу. Несколько полезных сервисов для тестирования проекта:
                                        +3

                                        и еще. В PHPStorm с установленным плагином Symfony можно указать в начале шаблона комментарий


                                        {# @controller BloggerBlogBundle:Page:contact #}

                                        и тогда в шаблоне автокомплит будет видеть все параметры передаваемые контроллером и по щелчку Ctrl+Mouse Left Click мы перейдем в контроллер, а при аналогичном щелчке по ссылке на шаблон перейдем в сам шаблон


                                        return $this->render('BloggerBlogBundle:Page:contact.html.twig', array(
                                            'form' => $form->createView()
                                        ));

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                        Самое читаемое