Part # 5 The model: Entity with Symfony

Entity with Symfony and an introduction to Service Containers and Dependency Injection

An entity is a basic class that holds data, here is how you would create a simple Car class

// src/My/HelloBundle/Entity/Car.php

namespace My\HelloBundle\Entity;
class Car
{
protected $id;
 protected $model;
 protected $color;
 protected $year;
}


This class doesn't persist to a database, it doesn't do CRUD operations, if you wan to let Doctrine do that here is the way to create this entity:

php app/console doctrine:generate:entity --entity="MyHelloBundle:Car"

Create all fields with their types (interget,string,smallint,datetime,etc...)

And answer:

Do you want to generate empty repository class? yes

The primary key id will be added by default

use Doctrine\ORM\Mapping as ORM;

/**
* My\HelloBundle\Entity\Car
*
* @ORM\Table()
* @ORM\Entity
*/
class Car
{

/**

* @var integer $id
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**

* @var string $model
*
* @ORM\Column(name="model", type="string", length=255)
*/
private $model;

/**
* @var string $color
*
* @ORM\Column(name="color", type="string", length=255)
*/
private $color;

/**
* @var integer $year
*
* @ORM\Column(name="year", type="integer")
*/
private $year;

/**
* Get id
*
* @return integer */
public function getId()
{
return $this->id;
}
// All the getters and setters ...
}

You can launch php app/console doctrine:generate:entity --entity="MyHelloBundle:Car" and anwser all the questions to add the fields
But this class is not linked to any database table, so change * @ORM\Table() by * @ORM\Table(name="car") which is the table name, if you don't do that the table name will be picked up from the class name.

Create a table with Doctrine

To print the sql query without executing it

php app/console doctrine:schema:update --dump -sql

To force the update and execute it

php app/console doctrine:schema:update --force

This command is very powerful because is going to create/update your database based on  the mapping information of your entities

Persisting objects to the database

 

Or how to save an entity to the database, to do so add a method inside a Controller

 

// src/My/HelloBundle/Controller/DefaultController.php

 

use My\HelloBundle\Entity\Car;

 

  /**
   * @Route("/test/", name="test")
   */

 

    public function testAction()
    {
     $car = new Car();
     $car->setModel("Ford");
     $car->setColor("White");
     $car->setYear("2010");

     $em = $this->getDoctrine()->getEntityManager();
     $em->persist($car);
     $em->flush();    
     print 'Created car id '.$car->getId();     
     exit();
    }

   

Then browse to /app_dev.php/test and you will see: Created car id 1

 

Get an object from the database

 

Let's say that you need to find a car in your database, usually you will do it with a query like "SELECT * FROM car WHERE id=1. Where are going to fetch a car object based on its id

 

Create a method show Action in the controller

 

 /**
  * @Route("/show/", name="show")
  */
public function showAction()
{
     $id=1;
     $car = $this->getDoctrine()
     ->getRepository('MyHelloBundle:Car')
     ->find($id);

     if (!$car)
     {
      throw $this->createNotFoundException('No car found for id '.$id);
     }     

 

     print 'Car model: '.$car->getModel();     
     exit();
    }

 

A repository is a PHP class that will fetch entities and store queries related to an entity, to find all cars int the table

 

$car = $this->getDoctrine()
     ->getRepository('MyHelloBundle:Car')
     ->findAll();

 

Create a Custom Repository Class

For the entity "Car" a repository class will have more complex query method inside, for example the method: findAllOrderedByName.

The repository class extends from the EntityRepository class we are going to use annotation to create, first, modify the annontation method Entity in the class "Car"

 * @ORM\Entity(repositoryClass="My\HelloBundle\Repository\CarRepository")

Then let Doctrine generate the repository for you:

php app/console doctrine:generate:entities My/HelloBundle/Entity/Car

// src/MyHelloBundle/Repository/CarRepository.php

namespace My\HelloBundle\Repository;

use Doctrine\ORM\EntityRepository;

class CarRepository extends EntityRepository
{
    // Define custom methods here
}

Create the Entity Manager

Entity Managers will help us to format data before passing it to controllers and call methods from the Repository.
We will create this manager with a basic method  to persist objects in the database:
// Base class manager

namespace My\HelloBundle\Manager;

abstract class BaseManager
{
protected function persistAndFlush($entity)
{
    $this->em->persist($entity);
    $this->em->flush();
}
}

//  Car manager class

 
namespace My\HelloBundle\Manager;
 
use Doctrine\ORM\EntityManager;
use My\HelloBundle\Manager\BaseManager;
use My\HelloBundle\Entity\Car;
 
class CarManager extends BaseManager
{
protected $em;
 
public function __construct(EntityManager $em)
{
$this->em = $em;
}
 
public function loadCar($carId) {
return $this->getRepository()
->findOneBy(array('id' => $carId));
}
 
/**
* Save Car entity
*
* @param Car $car
*/
public function saveCar(Car $car)
{
$this->persistAndFlush($car);
}
 
public function getPreviousCar($carId) {
return $this->getRepository()
->getAdjacentCar($carId, false)
->getQuery()
->setMaxResults(1)
->getOneOrNullResult();
}
 
public function getNextCar($carId) {
return $this->getRepository()
->getAdjacentCar($carId, true)
->getQuery()
->setMaxResults(1)
->getOneOrNullResult();
}
 
public function isAuthorized(Car $car, $memberId)
{
return ($car->getMember()->getId() == $memberId) ?
true:
false;
}
 
public function getPreviousAndNextCar($car)
{
return array(
'prev' => $this->getPreviousCar($car->getId()),
'car' => $car,
'next' => $this->getNextCar($car->getId())
);
}
 
public function getRepository()
{
return $this->em->getRepository('MyHelloBundle:Car');
}
 
}

The Service Container in Symfony 2

Service Container is a new concept in Symfony 2. A service is a task of function with a global scope in the whole framework. All services are available via the Service Container which is an object in the core of Symfony 2.

Services will allow us to get the object responsable for the email seinding for exemple.

Let's create a service for our CarManager, to do we need to declare the service in the service XML file in the folder: My/HelloBundle/Resources/config/services.xml

    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        My\HelloBundle\Manager\CarManager
   

   
       
           
       
   

Later on we can call the service from our code like this: $car = $this->get('my.car_manager')->loadCar($carId)

Dependency Injection

The main advantage of all this is flexibility, let's say that one day you want to change the Manager class to handle Cars and user a CarNewManager class instead.

All you will have to do is to change the parameter

My\HelloBundle\Manager\CarNewManager

And it will be operational right away whithout changes on the controllers or nothing.

Please read the full article here: http://symfony.com/doc/current/cookbook/bundles/extension.html

[Back to Learn Symfony]