Tuesday, June 28, 2016

Vagrant and ScotchBox

Developing on local machine brings problems like:
-  different software version on local machine than production(PHP, MySQL etc)
-  if you are messing with php.ini or other configuration file you need to uninstall it and install it from scratch.

Solution: use a virtual machine

Advanced solution: use a predefined virtual machine

For the advanced solution we need:

- VirtualBox : An x86 virtualization software package distributed under either the GNU GPL
- Vagrant : enables users to create and configure lightweight, reproducible, and portable development environments.
- ScotchBox - is a preconfigured Vagrant Box with a full array of LAMP Stack ( box.scotch.io )
-----------------------------------------------------------------------------------------------------------------------
You can search for other Vagrant boxes here: https://atlas.hashicorp.com/boxes/search
------------------------------------------------------------------------------------------------------------------------
Install VirtualBox and Vagrant on your machine.
Clone ScotchBox on your local machine:
    
git clone https://github.com/scotch-io/scotch-box.git my-project
 
Start the box! If this is your first time, the box will need to download. After that, everything should be ultra-fast to start:

vagrant up

 You can access the new web server on your virtual machine at this address:
 http://192.168.33.10/

Check the official website  https://box.scotch.io/  for details on how to connect with MySQL and SSH.

How to enable Zend OPCache on ScotchBox:

I lost some time until I found that I need to put opcache.enable = 1 also in this file: /etc/php5/apache2/conf.d/user.ini

https://github.com/scotch-io/scotch-box/issues/163

Monday, June 13, 2016

Symfony - How to apply validation based on user input using validation groups

In Symfony applications validation constraints are applied to the Entity and not to the Form. In some cases, however, you'll need to validate an object against only some constraints on that class. To do this, you can organize each constraint into one or more "validation groups", and then apply validation against just one group of constraints.

http://symfony.com/doc/current/book/validation.html#book-validation-validation-groups

Even better, you can determine which validation group should be applied based on the value filled in form by user:

http://symfony.com/doc/current/book/forms.html#groups-based-on-the-submitted-data

Let's say we have a   Product entity. Product entity has a 2 properties: description and category.
Depending on the "category "property different validation groups can be applied to 'description'. Symfony defines a group called "Default" in which are included all the validation which are not marked as part of any group.


<?php

class Product
{
    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text",  nullable=false)
     * @Assert\NotNull(groups={"imported"})
     */
    protected $description;

    protected $category;
}

I marked the NotNull validation as being part of "imported" group.

Now in the form class using the Product entity I need to put the logic based on which the validation groups are used:


<?php

use AppBundle\Entity\Product;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ProductType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       ....
    }
    // ...
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'validation_groups' => function (FormInterface $form) {
                $data = $form->getData();

                if ($data->getCategory() === 'Exotic fruits' ) {
                    return array('Default', 'imported');
                }

                return array('Default');
                },
        ));
    }
}

The code above basically says :
 - if category is "Exotic fruits" than apply "Default" and "imported" validations.
- otherwise apply only "Default" validations

Sometimes you need advanced logic to determine the validation groups. If they can't be determined by a simple callback, you can use a service:   http://symfony.com/doc/current/cookbook/validation/group_service_resolver.html