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



В этой части:

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
Пожалуйста, оцените качество руководства

Проголосовало 7 человек. Воздержавшихся нет.

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

Поделиться с друзьями
-->

Комментарии (52)


  1. maximkou
    28.05.2016 08:12
    +2

    Хорошо бы указать, что предпочтительнее создавать формы-классы, создание форм в контроллере — не лучшая практика. Формы-классы проще в тестировании и переиспользуемы. Об этом кстати описано в официальной документации.


    1. evheniy
      28.05.2016 13:08

      И на них можно вешать события, например, для для изменения данных перед обработкой или удаления лишних полей. symfony.com/doc/current/components/form/form_events.html


    1. padlyuck
      30.05.2016 12:30

      Не могли бы вы привести ссылку или показать пример? В документации, даже в разделе о формах в «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


      1. maximkou
        30.05.2016 20:50

        http://symfony.com/doc/current/book/forms.html#building-the-form читайте приписку


        1. padlyuck
          30.05.2016 21:29

          Так ведь в данном переводе форма так и создается, через формы-классы, или я не прав? Я совсем недавно начал разбираться с symfony, так что возможно я что-то упускаю


          1. maximkou
            30.05.2016 22:19

            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.


          1. maximkou
            30.05.2016 22:23

            извиняюсь. не заметил что пост обновили. в начальной версии поста использовался билдер в контроллере.


      1. Fesor
        31.05.2016 22:02

        (PostType::class, $post);

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


        1. padlyuck
          31.05.2016 23:02

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


  1. Big_Shark
    28.05.2016 11:01
    +4

    Несколько небольших изменений
    Конструкцию

    $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
    

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

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

    лучше заменить на
    $request->isMethod($request::METHOD_POST)
    


  1. M-A-XG
    28.05.2016 21:38
    -7

    Кто тоже считает, что Симфони слишком сложный, вам сюда:
    http://blog.kpitv.net/article/frameworks-1/

    Кто не считает, можете тоже сходит.
    Статья изменит вашу точку зрения на фреймворки.


    1. profesor08
      29.05.2016 03:01
      +1

      Не изменила. Фреймфорк это инструмент, как хочешь, так и пользуй. Никто не запрещает его изменять. И никто не запрещает писать свой инструмент. Главное, чтоб нравилось.


      1. M-A-XG
        29.05.2016 11:06
        -4

        А толку с инструмента, который не рабочий?
        Вы покупаете молоток в магазине, а потом дорабатываете его и половину выбрасываете? :)


        1. profesor08
          29.05.2016 11:24
          +2

          Рабочий.

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


          1. M-A-XG
            29.05.2016 12:13
            -2

            Фреймворк — это отдельно купить брусок и отдельно держание? :)
            О да, это сильно :)


            1. profesor08
              29.05.2016 13:28
              +1

              Инструментом либо умеешь пользоваться, либо пилишь молотком.


    1. maximkou
      29.05.2016 08:28
      +2

      Нас е**т, а мы крепчаем
      — это про вас.
      Вас минусуют за пиар своей статьи, а вы все равно вставляете ссылку на нее в каждом посте, который как-то связан с веб-разработкой.


      1. M-A-XG
        29.05.2016 10:56
        -3

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


        1. maximkou
          29.05.2016 12:34
          +3

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

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


          1. M-A-XG
            29.05.2016 13:01

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

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


            1. maximkou
              29.05.2016 13:45

              Фреймворки не панацея, согласен. И говнокод порой встречается.

              Но реалии бизнеса таковы, что, как правило:

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

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

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

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

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

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

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

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

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


              1. M-A-XG
                29.05.2016 15:52
                -2

                >Стартовать нужно в сжатые сроки, а иногда даже вчера.

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

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

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

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

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

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

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

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

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

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

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

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


                1. maximkou
                  29.05.2016 16:03

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

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

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

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

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

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

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

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

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

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

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

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


                  1. M-A-XG
                    29.05.2016 18:11
                    -1

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

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

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

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

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

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

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

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

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

                    При чем тут субъективно — не субъективно? Это мешание в кучу мух и котлет.


                1. franzose
                  30.05.2016 02:55

                  А где ваши 50 Кб можно посмотреть?


                  1. M-A-XG
                    30.05.2016 22:40
                    -4

                    Пока нигде потому что:
                    1. Это пока ноу-хау.
                    2. Я не хочу распространять код, если он будет труднообновляем. Нужно будет завернуть все в композитор, или как. У меня проблем с обновлениями моих сайтов пока нет, поэтому руки не доходят. :)
                    3. Я бы еще хотел как-то заработать на этом коде. :) Скорее всего не прямо. Возможно что-то вроде расширенной версии, как у нгинкса. :) В композиторе можно использовать сторонние репозитории с ключем доступа?
                    4. Как решают проблему конфликта классов сущностей другие? То есть какое-то расширение поставляет с собой какие-то сущности. Как обойти конфликты? Пользовательские сущности выносить в неймспейсы?
                    5. Перед выпуском в паблик стоило бы подчистить немного легаси код, там пару методов ядра.
                    6. Нужно написать документацию.
                    7. Я не знаю, как систему встретят, будут ли пользоваться. Если не будут, то смысла как бы и нет выкладывать. :)


        1. franzose
          30.05.2016 02:53
          +2

          Обойтись без фреймворков — это каждый раз собирать молоток для того, чтобы забить гвоздь? Причем молоток не проверенный годами и сотнями забитых гвоздей из дерева и металла, а из ДСП и пластика, который вот-вот сломается, возможно при первом же ударе по гвоздю :)


          1. M-A-XG
            31.05.2016 21:01

            1. Меня уровень проверки качества фреймворков не устроил.
            Они как китайские молотки, как бренды-пустышки (слышал, у Бугатти днище гниет за 2 года :) ). :)
            Почему берут фрейворки? Чтобы быстрее (якобы еще дешевле) состряпать продукт.
            В результате выходит черти что.
            Использовать фреймворк — это использовать кувалду, где нужен средний молоток.
            2. Каждый раз собирать молоток не нужно при грамотном подходе. Можно, конечно, мудохаться и в самописи, каждый раз переизобретая ранее собой же изобретенный велосипед, но это тупо.


            1. franzose
              01.06.2016 01:49

              Какой уровень проверки вы считаете приемлемым? Если это проект на Гитхабе, то его уровень можно посмотреть по количеству открытых/закрытых задач, покрытию тестами и отклику сообщества по тем или иным задачам и вопросам. Или вы что-то другое имеете в виду?


              1. M-A-XG
                01.06.2016 10:12
                -2

                Фреймворки слишком универсальны.


                1. franzose
                  01.06.2016 12:30
                  +1

                  На то они и фреймворки. Некоторые, как Symfony, можно разобрать на отдельные компоненты и взять только то, что нужно. И всё.


        1. Fesor
          31.05.2016 22:04
          +3

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

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


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


          1. M-A-XG
            01.06.2016 11:20

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


            1. Fesor
              01.06.2016 23:32
              +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 компонентов на самом деле из десятков). То есть нам нужно инвестировать свое время в изучение инструмента что бы его использование начиинало окупаться.


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


    1. MetaDone
      29.05.2016 10:15

      http://govnokod.ru/19878
      не изменит


      1. M-A-XG
        29.05.2016 10:43

        Вы автор? :)


        1. MetaDone
          29.05.2016 11:02

          http://govnokod.ru/19878#comment323654
          Нет, автор Вы, и стесняетесь признаваться


          1. M-A-XG
            29.05.2016 11:17

            Я имел в виду Вы автор того поста?


            1. MetaDone
              29.05.2016 11:35

              Жаль, но нет


    1. AngelZeruel
      29.05.2016 12:04
      +1

      Не первый раз вижу ссылку на эту статью. Более того, прочитал несколько раз и попытался осмыслить ее с нейтральной точки зрения. В этом свете возник вопрос — можно ли увидеть код (полностью или часть его) Вашего «ядра», о котором Вы упоминали? Ибо у меня складывается впечатление, что Ваше «ядро» не что иное, как еще один фреймворк.


      1. M-A-XG
        29.05.2016 12:25

        Я его не называю таким замараным словом, как фреймворк.
        И оно легко для понимания, в отличии от фрейморков.
        Содержит всего 50Кб.
        У меня используются нативные функции языка, а не так, что каждый фреймворк по сути является новым языком.
        А пишущие на фреймворках не умеют самостоятельно строить архитектуру.
        Также не мое ядро дергает пользовательский код, а пользовательский код дергает ядро.


        1. AngelZeruel
          29.05.2016 12:30

          Это замечательно. А можно все-таки пример увидеть, не часть кода, вырванного из контекста, а целостную картину (git репозитарий, листинг на сайте или др.)?


          1. M-A-XG
            29.05.2016 12:49
            +1

            1. Код пока ноу-хау.
            2. Там ничего как бы особенного нет:
            автолоадинг
            события
            работа с языками
            кеширование

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

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


            1. AngelZeruel
              29.05.2016 12:50
              +1

              Ясно-понятно, спасибо за комментарий


            1. franzose
              30.05.2016 03:20

              Ждём статей на Хабре!


        1. hanovruslan
          30.05.2016 08:03
          +2

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


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

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


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

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


          вот немногое


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

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


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


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


          1. M-A-XG
            01.06.2016 12:47

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

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

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

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

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

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

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

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

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

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

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

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

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

            Рад, что поняли :)


    1. DeLuxis
      30.05.2016 07:48
      +4

      > Cвоеобразное извращенное понимание МВЦ.
      MVC это архитектура, реализация может сильно отличаться. Это как у кирпичного дома должен быть бетонный фундамент, пропорции которого рассчитаны по такой-то формуле. А сам дом может быть чем угодно, хоть кирпичным небоскребом, главное соблюдать установленные правила.

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

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

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

      > Сложный дебаг, сложный аудит. Например нужно получить результирующий SQL-запрос.
      Xdebug и читайте документацию, там написано как получить SQL запрос.

      > Быстродейтсвие и потребление памяти.
      Никогда не было с этим проблем. Страница авторизованного пользователя с десятком уникальных виджетов грузится за 150 мс. Можно и 100 добиться. А страницы не авторизованных пользователей грузятся 5-1мс. Грамотное использование имеющихся механизмов кеширования.

      > Неудобно создавать статические страницы.
      Nginx прекрасно с этим справляется. Статичная страница на Yii создается 10 строчками кода.

      > Непонятные и лишние обертки для SQL.
      По вашему ORM не нужен?

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

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

      > Нету нормальных готовых компонентов, например меню. Меню каждый обязан написать сам. :)
      По сути CMS, они есть, см. github.

      > Нету добавления хлебных крошек.
      Виджеты есть.

      > При выпуске новых версий как правило отсутствует обратная совместимость.
      Между 5 и 7й версией PHP тоже не идеальная совместимость.
      Например внутри Yii 1.x с совместимостью все хорошо.

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

      > Чтобы обратиться к GET/POST/COOKIE/SERVER нужно использовать непойми зачем неудобные обертки.
      Безопасность и гибкость.


      1. M-A-XG
        01.06.2016 14:04

        >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.


      1. Fesor
        02.06.2016 10:42

        MVC это архитектура

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


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


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

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


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

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


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

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


  1. Rukuki_Ake
    31.05.2016 12:05

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

    <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'} }) }}
    


    1. antoscenco-vladimir
      02.06.2016 03:03

      спасибо, исправил