Symfony 3 should I upgrade or stay with Symfony 2

Everyone is excited about Symfony 3, including myself :)

Symfony 3 or Symfony 2?

Symfony 2.8 is exactly same as Symfony 3. But wait, then what’s the difference?

Symfony 3 mostly have new directory structure for logs, cache and console. Also all the previous deprecated functions are removed.

Should I upgrade then, if its same?

No!!!, Even tho it is exactly same, but knowing all the deprecated functions are removed on Symfony 3, you should ask yourself.

Are you going to be using third party bundles?

and thous bundles are update-to-date with Symfony 3. Most likely you will get the answer no.

having third party bundles on Symfony 3 will break your application, If it was using any of the deprecated function.

Soon we can upgrade when everyone upgrades their bundles.

Complete list of changes 

Symfony3 Auto Wiring – Auto Creating Dependency Services

Previously if you ever had dependency for your object, you had to make sure the names for dependency services are correctly passed down to your new service before you can start using it.

Since Symfony 2.8 which is official exact version of Symfony 3 (removing all the deprecated functions).

Now you can create services without worrying about dependency injection services with auto wiring feature. The key feature in auto wiring is, if one of your dependency injection service does not exist, then it will auto create it and inject it.

Let’s assume we have following object, which needs to be created as service.
namespace AppBundle\Service;

use AppBundle\Service\House;

class Room
{
    private $house;

    public function __construct(House $house)
    {
        $this->house = $house;
    }
}

Old way creating service
services:
    house:
        class: AppBundle\Service\House

    room:
        class: AppBundle\Service\Room
        arguments:
            - @house
New way with auto wiring
services:
    room:
        class: AppBundle\Service\Room
        autowire: true

The above example is very simple. Now imagine you have 5 or even 6 different dependency injections, you would have to waste time on getting each dependency service names and on top, if you later on decided to change the or remove dependency from your object, then you have to update services as well. With auto wiring you don’t have to worry about anything, it worries for you.

What about Performance?

It is exactly as same as before. Compiler builds and save everything in cache, just like before.

Change input name of the form fields in Symfony3

Remove form type name from the form

Sometimes we need to integrate third party application or form, which requires us to remove any array type form names. 

Problem

Normal form will create FormTypeName[fieldName]

<input type="text" value="" name="formTypeName[fieldName]">

Our final outcome should look like field name only without any form type name.

<input type="text" value="" name="fieldName">

Solution 

Create the form using createNamed method.

$form = $this->get('form.factory')->createNamed(null, new MyFormType(), $dataObject, $formOptions);

When you pass first argument as null, it will remove form type name and make fields as field name only.

Solution 2

You can also change your formType and return blockPrefix null.

class MyFormType extends AbstractType
{
    ...

    /**
     * This will remove formTypeName from the form
     * @return null
     */
    public function getBlockPrefix() {
        return null;
    }
}

I recommend first solution.

Symfony3 Container Dependency Injection

It’s 2016, you can use trait which will help you extend same class with multiple libraries.

I keep seeing container class get extended into another class, which then extends to another, before you know it you have extended 5 different classes just to use libraries.

What if you can include 5 different libraries into 1 object without extending? Well you can use it with php5.4 trait feature.

Container dependency injection trait class

    
    namespace iBasit\ToolsBundle\Utils\Lib;
    
    use Doctrine\Bundle\DoctrineBundle\Registry;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    trait Container
    {
        private $container;
    
        public function setContainer (ContainerInterface $container)
        {
            $this->container = $container;
        }
    
        /**
         * Shortcut to return the Doctrine Registry service.
         *
         * @return Registry
         *
         * @throws \LogicException If DoctrineBundle is not available
         */
        protected function getDoctrine()
        {
            if (!$this->container->has('doctrine')) {
                throw new \LogicException('The DoctrineBundle is not registered in your application.');
            }
    
            return $this->container->get('doctrine');
        }
    
        /**
         * Get a user from the Security Token Storage.
         *
         * @return mixed
         *
         * @throws \LogicException If SecurityBundle is not available
         *
         * @see TokenInterface::getUser()
         */
        protected function getUser()
        {
            if (!$this->container->has('security.token_storage')) {
                throw new \LogicException('The SecurityBundle is not registered in your application.');
            }
    
            if (null === $token = $this->container->get('security.token_storage')->getToken()) {
                return;
            }
    
            if (!is_object($user = $token->getUser())) {
                // e.g. anonymous authentication
                return;
            }
    
            return $user;
        }
    
        /**
         * Returns true if the service id is defined.
         *
         * @param string $id The service id
         *
         * @return bool true if the service id is defined, false otherwise
         */
        protected function has ($id)
        {
            return $this->container->has($id);
        }
    
        /**
         * Gets a container service by its id.
         *
         * @param string $id The service id
         *
         * @return object The service
         */
        protected function get ($id)
        {
            if ('request' === $id)
            {
                @trigger_error('The "request" service is deprecated and will be removed in 3.0. Add a typehint for Symfony\\Component\\HttpFoundation\\Request to your controller parameters to retrieve the request instead.', E_USER_DEPRECATED);
            }
    
            return $this->container->get($id);
        }
    
        /**
         * Gets a container configuration parameter by its name.
         *
         * @param string $name The parameter name
         *
         * @return mixed
         */
        protected function getParameter ($name)
        {
            return $this->container->getParameter($name);
        }
    }

Your custom object, which will be service.

    namespace AppBundle\Utils;
    
    use iBasit\ToolsBundle\Utils\Lib\Container;
    
    class myObject
    {
        use Container;
    }

Your object service settings

     myObject: 
            class: AppBundle\Utils\myObject
            calls:
                - [setContainer, ["@service_container"]]

Call your service in controller

    $myObject = $this->get('myObject');

Quick Setup Mailgun with CloudFlare + Gmail

Mailgun Setup

  • Create a Mailgun account
  • Add your domain name (no www)
    domain.com
  • Keep the page open and open a new tab to CloudFlare

Cloudflare

  • Choose your site and select DNS Settings
  • Add the two Text records
  • Add the CNAME record
    • Make sure the cloudflare cloud is gray and not orange/active
  • Add the two MX records
    • Name domain.com (no www)
    • Mail handled by mxa.mailgun.org or mxb.mailgun.org

Back at Mailgun

  • Click add
    • Click Check DNS Records Now
  • It’ll tell you once it detects the updated DNS records

Email Forwarding

  • From Mailgun, choose Routes
  • Create Your First Route
  • Priority 10
  • Filter Expression This is where you list the email address you want to forward to gmail
    match_recipient("you@domain.com")
  • Actions This is the gmail address you want to receive your mail
    forward("me@gmail.com")
  • Description Name it something so you remember what it’s for

Use Gmail to send mail from your domain

  • Log in to Gmail and go to settings
  • Go to Accounts and Import
  • Go to Send mail as and select add another email you own
    • name: Anything you want
    • email address: name@domain.com (this should be the email you set up in the steps before)
    • Leave treat as an alias checked
    • Click Next Step
    • For the following info you’ll need to login to mailgun and use the info under Domain Information
    • SMTP Server Use SMTP Hostname from Mailgun
    • Username Use Default SMTP Login from Mailgun
    • Password Use Default Password from Mailgun
    • Leave Secured connection using TLS selected
    • Click add account
  • Once it’s verified you should be able to compose emails and list your new email in the from line so nobody needs to know it’s coming from your personal gmail account.