I'm using Symfony2.3 and I currently using EntityManager as shown inside __construct()
Which its a better aproach using EntityManager from __construct() or using inside each method ? as shown in public indexAction()
/**
* QuazBar controller.
*
*/
class QuazBarController extends Controller
{
public function __construct()
{
$this->em = $GLOBALS['kernel']->getContainer()->get('doctrine')->getManager();
}
/**
* Lists all QuazBar entities.
*
*/
public function indexAction(Request $request)
{
$session = $request->getSession();
$pagina = $request->query->get('page', 1);
$em = $this->getDoctrine()->getManager();
}
If you must have the EntityManager available in your constructor, a good way to get it is injecting it to the constructor.
To do this you must define your controller as a service.
# src/Acme/DemoBundle/Resources/config/services.yml
parameters:
# ...
acme.controller.quazbar.class: Acme\DemoBundle\Controller\QuazBarController
services:
acme.quazbar.controller:
class: "%acme.controller.quazbar.class%"
# inject doctrine to the constructor as an argument
arguments: [ #doctrine.orm.entity_manager ]
Now all you have to do is modify your controller:
use Doctrine\ORM\EntityManager;
/**
* QuazBar controller.
*
*/
class QuazBarController extends Controller
{
public function __construct(EntityManager $em)
{
$this->em = $em;
}
// ...
}
If you do not require the Entity Manager in the constructor, you can simply get it using the Dependency Injection Container from any method in your controller:
$this->getDoctrine()->getManager();
OR
$this->container->get('doctrine')->getManager();
Controller/setter injection is a good choice because you are not coupling your controller implementation to the DI Container.
At the end which one you use is up to your needs.
In symfony 2.3, I believe that a connection to the doctrine entity manager is built into the controller class.
$em = $this->getDoctrine()->getManager();
Best practice is to make this call in the controllers when you need it. If it's simply convenience, you could derive a controller class and add something like getEm() if you find that too odious.
Often, your own controller class is a good idea, for baking in security restrictions and making your code more DRY.
Can we define a constructor in the controller class ? The doctrine is a service. Does it make any difference to get doctrine in constructor or to get wherever you want want it from di. Both ways you get the same service. Why do you want to inject the em that is already injected.
Related
I posted another question trying to find a way to statically access a repository class outside of a controller in a custom "helper" class.
So far the only way I have figured out how to achieve this is using the code below. If anyone wants to chime into the other question about "best practice" or "design patterns" please do.
I opened this question to seek the best method on having a singleton service (?) loaded when symfony boots so other classes can access it statically without any dependency injection. I haven't had much luck on finding any official docs or common practices. I know singleton is anti practice, but is the method below the best way, or is there a more ideal solution?
services.yml
parameters:
entity.device: Asterisk\DbBundle\Entity\Device
services:
asterisk.repository.device:
class: Asterisk\DbBundle\Entity\Repositories\DeviceRepository
factory: ["#doctrine.orm.asterisk_entity_manager", getRepository]
arguments:
- %entity.device%
tags:
- {name: kernel.event_listener, event: kernel.request, method: onKernelRequest}
DeviceRepository
class DeviceRepository extends \Doctrine\ORM\EntityRepository
{
/** #var ExtendedEntityRepository */
protected static $instance;
public function __construct(EntityManager $entityManager, ClassMetadata $class)
{
parent::__construct($entityManager, $class);
if(static::$instance instanceof static == false)
static::$instance = $this;
}
public static function getInstance()
{
return static::$instance;
}
public function onKernelRequest($event)
{
return;
}
}
Glad to see you are not running around anymore.
Your approach is not going to work unless someone grabs the repository out of the container first so self::$instance is initialized. But you really don't want to do this anyways. Super hacky.
You want to inject the repository service into your kernel listener. Trying to make the repository act as a kernel listener is just not a good design. So just make a service for your repository and then a second one for the listener. It may seem a bit strange at first but it really does work well in practice and it's the way S2 is designed.
If for some reason you are stuck with the notion that you have to be able to access the container globally then be aware that your kernel is defined globally(take a look at app.php) and it has a getContainer method in it.
$repo = $_GLOBAL['kernel']->getContainer()->get('asterisk.repository.device');
But again, there should be no need to do this.
==============================
Update - It looks like you are trying to use the listener functionality just to setup singletons. You should try to avoid singletons but if you really think you need them then the global access to the kernel can be used:
class DeviceRepository extends \Doctrine\ORM\EntityRepository
{
/** #var ExtendedEntityRepository */
protected static $instance;
public static function getInstance()
{
if (!static::$instance) {
static::$instance = $_GLOBAL['kernel']->getContainer()->get('asterisk.repository.device');
}
return static::$instance;
}
Poor design but at least it get's rid of the listener hack and it avoids creating the repository until it's actually needed. It aslo means you can access the repository from commands (listeners are not setup when commands are called).
I do not understand what the profit will be about this method. The idea of the servicecontainer is to make just one instance of each class and give a reference (or pointer if you like) to any method who asks to use this same instance. Let me proof it:
Service definition:
// app/config.yml
services:
app.test:
class: Vendor\AppBundle\Service\Test
and a custom class:
// src/AppBundle/Service/Test.php
namespace AppBundle/Service;
class Test {
public $test = 0;
}
and a controller:
// src/AppBundle/Controller/DefaultController
namespace AppBundle/Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction()
{
$instance1 = $this->get('app.test');
$instance2 = $this->get('app.test');
$instance1->test = 1;
echo $instance2->test; // RETURNS 1 !!!
exit;
}
I would like to be able to use the PersistentObject described here http://www.doctrine-project.org/blog/a-doctrine-orm-odm-base-class.html during development of a Symfony2 project, to avoid creating and deleting getters and setters endlessly whilst the database and entity design are in flux.
Where in a Symfony2 project does one 'configure' the ObjectManager, as suggested in the brief documentation (code quote below)? Should it be in the controller, and if so, what would it look like?
$entityManager = EntityManager::create(...);
PersistentObject::setObjectManager($entityManager);
I cannot find any working examples (although I did find this parallels example for the Zend2 framework on stackoverflow: Using PersistentObject from Doctrine in Zend Framework
Thanks for your time!
The PersistentObject is an object which you don't manually have to persist. It thereby provides magic getters and setters using php's __call() method.
You simply extend the Object in your entity class and use it inside your controller. without the need to generate getters and setters.
example entity
<?php
namespace Vendor\YourBundle\YourEntity;
use Doctrine\Common\Persistence\PersistentObject;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\Mapping as ORM;
class YourEntity extends PersistentObject
{
// i added the constructor in order to save the setObjectManager()
// call in the the controller
public function __construct(ObjectManager $om)
{
$this->setObjectManager($om);
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=100)
*/
protected $name;
// ... more properties
}
example controller action
class YourController extends Controller
{
public function yourAction($name)
{
$em = $this->get('doctrine')->getManager('default');
$entity = new YourEntity($em); // __construct calls setObjectManager($em)
$entity->setName($name); // magic setter is used here
// ... no need for $em->persist($entity);
$em->flush(); // $entity is being persisted.
}
// ...
You get the doctrine entity manager inside a symfony controller using one of ...
$em = $this->get('doctrine')->getManager(); // gets default manager
$em = $this->get('doctrine')->getManager('default'); // same as above
$em = $this->getDoctrine()->getManager(); // using alias
I am trying to write an event listener that needs access to the users permission level. In the controller I use the following code
Code:
$securityContext = $this->container->get('security.context');
if($securityContext->isGranted('ROLE_USER')){
//Do Something
}
But outside of a controller I can't work out how to get the security context. Is it possible?
The best way to do this is using (as phpisuber said) dependency injection through the Service Container. But, instead of injecting the entire container (which is considered bad practice as it makes your entire class less testable and breaks loose coupling) you should inject the security.context service like so:
acme_foo.bar_service:
class: %acme_foo.bar_service.class%
arguments:
- #security.context
Your service can be something like this:
<?php
namespace Acme\FooBundle\Service;
use Symfony\Component\Security\Core\SecurityContext;
class BarService
{
/**
* #var SecurityContext
*/
protected $context;
/**
* #param SecurityContext $context
*/
public function __construct($context)
{
$this->context = $context;
}
public function doSomething()
{
return $this->context->isGranted('ROLE_USER');
}
}
There is two ways to get it outside a controller:
Dependency Injection:
This is the correct way to do it, all you need is in the documentation here.
mybundle.model.mymodel:
class: %mybundle.model.myclass%
arguments: [#servicecontainer]
Quick and Dirty:
global $kernel;
$securityContext = $kernel->getContainer()->get('security.context');
I know this post is a little dated, but it still came up as one of the first results on Google.
The answers in this post reference the SecurityContext class, which is no longer supported as of Symfony 2.6. The accepted answer for this post is misleading because of the class deprecation.
Try this code from this answer:
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use YourNameSpace\UserBundle\Entity\User;
class LoginController extends Controller{
public function registerAction()
{
$user = //Handle getting or creating the user entity likely with a posted form
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.token_storage')->setToken($token);
$this->get('session')->set('_security_main', serialize($token));
}
}
For example i have algorithmic function, which calculates specific hash-code. Function itself is 300+ lines of code. I need to use that functions many times in many different controllers in my bundle. Where can i store my calculate_hash() to use it in my bundle ? Can i access it from other bundles ?
Can i also write global calculate_hash() which have access to entity manager ?
Didn't find my answer here.
In the Symfony2 world, this is clearly belonging to a service. Services are in fact normal classes that are tied to the dependency injection container. You can inject them the dependencies you need. For example, say your class where the function calculate_hash is located is AlgorithmicHelper. The service holds "global" functions. You define your class something like this:
namespace Acme\AcmeBundle\Helper;
// Correct use statements here ...
class AlgorithmicHelper {
private $entityManager;
public function __construct(EntityManager $entityManager) {
$this->entityManager = $entityManager;
}
public function calculate_hash() {
// Do what you need, $this->entityManager holds a reference to your entity manager
}
}
This class then needs to be made aware to symfony dependecy container. For this, you define you service in the app/config/config.yml files by adding a service section like this:
services:
acme.helper.algorithmic:
class: Acme\AcmeBundle\Helper\AlgorithmicHelper
arguments:
entityManager: "#doctrine.orm.entity_manager"
Just below the service, is the service id. It is used to retrieve your service in the controllers for example. After, you specify the class of the service and then, the arguments to pass to the constructor of the class. The # notation means pass a reference to the service with id doctrine.orm.entity_manager.
Then, in your controller, you do something like this to retrieve the service and used it:
$helper = $this->get('acme.helper.algorithmic');
$helper-> calculate_hash();
Note that the result of the call to $this->get('acme.helper.algorithmic') will always return the same instance of the helper. This means that, by default, service are unique. It is like having a singleton class.
For further details, I invite you to read the Symfony2 book. Check those links also
The service container section from Symfony2 book.
An answer I gave on accesing service outside controllers, here.
Hope it helps.
Regards,
Matt
Braian in comment asked for Symfony 3 answer, so here is one Symfony 3.3 (released May 2017):
1. The original class remains the same
namespace Acme\AcmeBundle\Helper;
use Doctrine\ORM\EntityManager;
final class AlgorithmicHelper
{
/**
* #var EntityManager
*/
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function calculateHash()
{
// Do what you need, $this->entityManager holds a reference to your entity manager
}
}
2. Service registration is much simpler
# app/config/services.yml
services:
_defaults: autowire # this enabled constructor autowiring for all registered services
Acme\AcmeBundle\Helper\AlgorithmicHelper: ~
3. Use constructor injection to get the service
use Acme\AcmeBundle\Helper\AlgorithmicHelper;
class SomeController
{
/**
* #var AlgorithmicHelper
*/
private $algorithmicHelper;
public function __construct(AlgorithmicHelper $algorithmicHelper)
{
$this->algorithmicHelper = $algorithmicHelper;
}
public function someAction()
{
// some code
$hash = $this->algorithmicHelper->calculateHash();
// some code
}
}
You can read about Symfony 3.3 dependency injection (in this case registering services in config and using it in controller) news in these 2 posts:
https://www.tomasvotruba.cz/blog/2017/05/07/how-to-refactor-to-new-dependency-injection-features-in-symfony-3-3/
https://symfony.com/blog/the-new-symfony-3-3-service-configuration-changes-explained
I am integrating Zend Framework and Doctrine 2.
The question is, in my controllers and view, in need to access the model. I can do all this through a single instance of the EntityManager.
Where do I store this instance ?
Zend_Registry ? That's where it is now, it is accessible from everywhere, but not really practical : $em = Zend_Registry::get('EntityManager');
As a controller and view property ? That would be accessible as $this->em, I like this
Create a factory class that will return the instance ? $em = My\EntityManager\Factory::getInstance();. Encapsulation is good, but long to type...
Is the EntityManager a Singleton already ? -> (update) not it is not
I wouldn't recommend using the EntityManager directly in your Controllers and Views. Instead, use a Service layer and inject the EntityManager it that.
I have two custom action helpers, one to retrieve Repositories and one for Services. Each action hold a reference to the EntityManager and inject it accordingly before handing it back to the Controller.
Not my actual code but something like this (not tested):
My/Controller/Action/Helper/Service.php
<?php
namespace My\Controller\Action\Helper;
use Doctrine\ORM\EntityManager;
class Service extends \Zend_Controller_Action_Helper_Abstract
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function direct($serviceClass)
{
return new $serviceClass($this->em);
}
}
You can write a similar Action Helper to retrieve Repositories.
Then, register the helper in your bootstrap (where we also have access to the EntityManager):
<?php
use Zend_Controller_Action_HelperBroker as HelperBroker,
My\Controller\Action\Helper\Service;
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function _initActionHelpers()
{
$this->bootstrap('doctrine');
$em = $this->getResource('doctrine');
HelperBroker::addHelper(new Service($em));
}
}
Now write a simple Service.
My/Domain/Blog/Service/PostService.php
<?php
namespace My\Domain\Blog\Service;
use Doctrine\ORM\EntityManager,
My\Domain\Blog\Entity\Post;
class PostService implements \My\Domain\Service
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function createPost($data)
{
$post = new Post();
$post->setTitle($data['title']);
$post->setContent($data['content']);
$this->em->persist($post);
$this->em->flush(); // flush now so we can get Post ID
return $post;
}
}
And to bring it all together in a controller action:
<?php
class Blog_PostController extends Zend_Controller_Action
{
private $postService;
public function init()
{
$this->postService = $this->_helper->Service('My\Domain\Blog\PostService');
}
public function createPostAction()
{
// normally we'd get data from the actual request
$data = array(
"title" => "StackOverflow is great!",
"content" => "Imagine where I'd be without SO :)"
);
// and then validate it too!!
$post = $this->postService->createPost($data);
echo $post->getId(); // Blog post should be persisted
}
}
Since the EntityManager is usually created and configured during bootstrap - either as the return value of an explicit _initDoctrine() call or by using an application resource - storing it in the Bootstrap seems to make the most sense to me. Then inside a controller, it is accessible as:
$em = $this->getInvokeArg('bootstrap')->getResource('doctrine');
I see a lot of examples of accessing bootstrap via the front controller singleton:
$em = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('doctrine');
which has the advantage that works everywhere.
Take a look at the integration provided by the Bisna package, written by one of the Doctrine 2 contributes. It is at https://github.com/guilhermeblanco/ZendFramework1-Doctrine2
It allows you to configure Doctrine in your application.ini. It uses an application resource plugin to process the ini settings. I have written documentation for Bisna. It may be integrated into the package by the time you read this. If not, you can find it at https://github.com/kkruecke/ZendFramework1-Doctrine2, in the bisna-documentation/html subdirectory of that package. I have also put the documentation a http://www.kurttest.com/zfa/bisna.html (although this may be temporary).
I store the Entity Manager in Zend_Registry and then I've also created an action helper which I call in my controllers.
Zend_Registry i think is a goods idea.
Basically it is a bad idea to access EM from view, if your really need this feature, your can create a view helper, and use it