Writing plugins

    As always, it all started with the fact that ready-made solutions from the plugin repository for symfony did not suit me . More precisely, ready-made solutions simply did not work, but this is a completely different story.

    Today I would like to share my experience and knowledge on how to write plugins for symfony. And since I will describe everything that needs to be done, using my own example, a side effect will be additional information on how to create widgets and validators for forms (sfForm).

    And so below you will find out:
    • How to create plugins
    • How to write widgets for sfForm
    • How to write validators for these widgets

    We are writing a plugin! In my case, this is a plugin for displaying captcha in the registration form (in any form, it doesn’t matter). I would like to say that the plugin is the same module, with the only condition that all scripts (files) are combined in one place, namely in the plugins directory of the project. In connection with this first step, you need to create a directory with a name identical to the name of your plugin, in my case it is “sfVirCaptchaPlugin”.

    I wanted versatility when creating the plugin and the main settings I put into the configuration file. To do this, I created the “config” subdirectory in the “sfVirCaptchaPlugin” directory, and accordingly created the “app.yml” file with approximately the following contents:
    all:
    sfVirCaptcha:
    width: 40
    height: 20


    Then I started writing directly the class generating the captcha (I’ll probably omit the logic itself, if anyone is interested in how to make captcha and stuff, I’m sure that a search in the hub will give you at least 10 results, this post is about another). And so we create one more subdirectory “lib” (we must warn that the auto-loader in symfony does not parse all directories at all, so try to adhere to standard directory names). In the "lib" create the file "sfVirCaptcha.php":

    class sfVirCaptcha
    {
    public function __construct()
    {
    // Те самые значения из app.yml
    $this->width = sfConfig::get('app_sfVirCaptcha_width');
    $this->height = sfConfig::get('app_sfVirCaptcha_height');
    }

    /**
    * Генерация капчи
    *
    * @return image
    */
    public function get()
    {
    $captcha = imagecreate($this->width, $this->height);
    // ...процесс генерации картинки опускаю, дабы избежать флуда в комментариях ;)
    // Сохраняем код в сессию для последующей проверки
    sfContext::getInstance()->getUser()->setAttribute('sfVirCaptcha', $code);
    return $captcha;
    }

    /**
    * Проверка полученного из формы кода
    */
    public static function Validate($value)
    {
    if (sfContext::getInstance()->getUser()->getAttribute('sfVirCaptcha') == $value) {
    return true;
    }
    return false;
    }
    }

    ?>


    Thus, we are ready for the class that generates captcha and checks the entered code for correctness. It's time to do the action, which we will give the picture (kachpu). We create the “modules” directory, in it the “sfVirCaptcha” directory, then “actions”, and already there the “actions.class.php” file containing:

    class sfVirCaptchaActions extends sfActions
    {
    public function executeIndex(sfWebRequest $request)
    {
    // Установка в заголовки страницы Content-type
    $this->getResponse()->setContentType('image/png');
    // Получение капчи
    $sfVirCaptcha = new sfVirCaptcha();
    // Выдача (отображение) капчи
    imagepng($sfVirCaptcha->get());
    // Отказ от использования layout'ов и template'ов в данном action'е
    return sfView::NONE;
    }
    }


    Now at the request of project / sfVirCaptcha we get a finished picture (captcha).

    The next step in creating a plugin is to define the widget for the form. To do this, create the file “sfWidgetFormVirCaptcha.php” in the previously created “lib” directory:

    // Создаем класс, который наследуется от sfWidgetForm
    class sfWidgetFormVirCaptcha extends sfWidgetForm
    {
    // Определяем стандартный для виджетов метод configure
    protected function configure($options = array(), $attributes = array()) {
    $this->addOption('type', 'text');
    $this->setOption('is_hidden', false);
    }

    // Рендерим html-код, который будет вставлен непосредственно в форму
    public function render($name, $value = null, $attributes = array(), $errors = array()) {
    $result = $this->renderTag('input', array_merge(array('type' => $this->getOption('type'), 'name' => $name, 'value' => $value), $attributes));
    $result .= '  ';
    return $result;
    }
    }

    ?>


    Without delay, we create a validator for this widget, create the file “sfValidatorVirCaptcha.php” in the same directory “lib”:
    // Создаем класс, который наследуется от sfValidatorBase
    class sfValidatorVirCaptcha extends sfValidatorBase {
    // Определяем стандартный для валидаторов метод configure
    protected function configure($options = array(), $messages = array()) {
    parent::configure($options, $messages);
    }

    // Метод, который непосредственно валидирует переданное значение
    protected function doClean($value) {
    $value = (string) $value;
    // Пользуемся прежде созданным методом Validate класса sfVirCaptcha
    if (!sfVirCaptcha::Validate($value)) {
    throw new sfValidatorError($this, 'invalid', array('value' => $value));
    }
    return $value;
    }
    }

    ?>


    And so! The plugin is ready! Now you can insert captcha in any shape. Registration form example:

    class UserRegistrationForm extends sfForm
    {
    public function configure()
    {
    $this->setWidgets(array(
    'login' => new sfWidgetFormInput(),
    'password' => new sfWidgetFormInputPassword(),
    'captcha' => new sfWidgetFormVirCaptcha(),
    ));

    $this->setValidators(array(
    'login' => new sfValidatorString(array('min_length' => 3, 'required' => true)),
    'password' => new sfValidatorString(array('min_length' => 3, 'required' => true)),
    'captcha' => new sfValidatorVirCaptcha(),
    ));

    $this->widgetSchema->setNameFormat('user[%s]');
    }
    }



    That's all. But no ... I forgot that it is necessary to register this plugin in settings.yml, and clean the cache, but after that you can safely use it.

    PS It is written a little crumpled, but the head is already working poorly in the evening, and the desire to share experience is huge. If anyone is not clear about something, ask, I will definitely try to answer.

    Also popular now: