0

From the examples I'm finding in the Symfony docs, it looks like the typical thing to do when needing to save data is something like in the controller class:

public function createAction(){
    $product = new Product();
    $product->setName('Amy Keyboard');
    $product->setPrice(24.99);
    $product->setDescription('Ergonomic and stylish!');
    $em = $this->getDoctrine()->getManager();
    $em->persist($product);
    $em->flush();
    return $this->render('index.html.twig'); 
}

It would be really great to not have to type those 3 $em lines in every single controller method! And it would be even sweeter to move all of this logic to a class somewhere else and then just call $product->saveProduct($data)! What is the best option here?

Amy Lashley
  • 416
  • 4
  • 11
  • Do you mean to save lines of code that `$data` would contain an array of items that you want to set in the Product Entity? For example `$data` would contain "Name, Price, Description". If this is the way you want to go let us know. – Alvin Bunk May 19 '17 at 22:09
  • Might want to build a few more actions before focusing on refinement. The first line just gets the entity manager. Most actions will probably need the manager for queries and what not anyways. The persist line is only needed for new entities. And you only need the flush when updating the database. – Cerad May 20 '17 at 01:13
  • And if you really want to save some lines then $product = new Product($name,$description,$price); – Cerad May 20 '17 at 01:15

2 Answers2

3

I usually create a manager class e.g. ProductManager and register it as service. I inject the EntityManager via setter injection and implement all the methods I need.

In your case this would look similar to this:

AppBundle/Product/ProductManager

namespace AppBundle\Product;

use Doctrine\ORM\EntityManager;

class ProductManager {

    /** @var EntityManager */
    private $entityManager;

    public function setEntityManager (EntityManager $entityManager) 
    {
        $this->entityManager = $entityManager;
    }

    public function getAll()
    {
        return $this->entityManager->createQuery('SELECT p FROM '.Product::class.' p')
            ->getResult();
    }

    public function add(Product $product, $flush = true)
    {
        $this->entityManager->persist($product);

        if ( $flush ) { 
            $this->entityManager->flush($product);
        }
    }

    public function byId($id)
    {
        // Fetch a product by id (note: No need to use DQL or the EntityRepository here either!)
        return $this->entityManager->find(Product::class, $id);
    }
}

app/config/services.yml

services:
    app.product_manager:
        class: AppBundle\Product\ProductManager
        calls: 
            - [setEntityManager, ['@doctrine.orm.entity_manager']]

Controller

public function createAction(){
    $product = new Product();
    $product->setName('Amy Keyboard');
    $product->setPrice(24.99);
    $product->setDescription('Ergonomic and stylish!');

    // add the product
    $this->get('app.product_manager')->add($product);

    return $this->render('index.html.twig'); 
}
lordrhodos
  • 2,689
  • 1
  • 24
  • 37
  • Is there a reason you don't just do these things in the repository class? I could easily be wrong, but this just seems like the exact kind of thing the repository is designed for. – JacobW May 20 '17 at 00:25
  • Thank you! I do have the same question as Jacob though. Could this same system be done using a repository class? I'm basically looking for my M of my MVC (I'm coming from CakePHP and I love the way they handle all of the dirty work for you). It would be great to not have to have a whole other file. But everything else you laid out here sounds great! – Amy Lashley May 20 '17 at 21:15
  • please check out the purpose of the [EntityRepository](http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.EntityRepository.html) class. It is not used by doctrine at all. It more or less just wraps the entity manager and unity of work. On top of that it provides some generic convenience methods. I am not a fan of the magic **findBy** methods as it seduces developers to go the _easy_ way. I like it if you have more control and restriction when accessing the orm layer. Of course you can use the Repository as starting point, define it as service and use it in the controller. – lordrhodos May 21 '17 at 21:15
  • 1
    If you follow the approach of the [repository pattern using a collection-like interface](https://martinfowler.com/eaaCatalog/repository.html) you will see that the EntityRepository just supports part of the approach. So if you need to extend it with methods adding a product do why not start with a clean approach. Wouter de Jong has written a [great article wrapping up the treat the repository as a collection approach](http://wouterj.nl/2016/12/repositories-are-just-collections/) – lordrhodos May 21 '17 at 21:30
0

Take a look at the Propel project if you want something like $product->save() but it is a totally different approach. This is the official bundle https://github.com/propelorm/PropelBundle/blob/3.0/README.markdown

ste
  • 1,479
  • 10
  • 19