Using Doctrine in a service Symfony2 - symfony

How do I use Doctrine in a class outside from the controller?
$event = $this->getDoctrine()
->getRepository('AtotrukisMainBundle:Event')
->findByCreatedBy($userId);
if (!$event) {
throw $this->createNotFoundException(
'You have no events'
);
}
The code above works perfectly in a controller, but in a service I get error: Attempted to call method "getDoctrine" on class "Atotrukis\MainBundle\Service\EventService" in /var/www/src/Atotrukis/MainBundle/Service/EventService.php line 15.
How do I make it work?
services.yml:
services:
eventService:
class: Atotrukis\MainBundle\Service\EventService
Part from the EventController:
public function readMyEventsAction()
{
$user = $this->getDoctrine()->getRepository('AtotrukisMainBundle:User')
->findOneById($this->get('security.context')->getToken()->getUser()->getId());
$userEvents = $this->get('eventService')->readUserEvents($user);
return $this->render('AtotrukisMainBundle:Event:myEvents.html.twig', array('events' => $userEvents));
}
EventService.php:
<?php
namespace Atotrukis\MainBundle\Service;
class EventService{
public function create(){
}
public function readUserEvents($userId){
$event = $this->getDoctrine()
->getRepository('AtotrukisMainBundle:Event')
->findByCreatedBy($userId);
if (!$event) {
throw $this->createNotFoundException(
'You have no events'
);
}
return $userId;
}
}

You can pass it as an argument in your service declaration:
services:
eventService:
class: Atotrukis\MainBundle\Service\EventService
arguments: ["#doctrine.orm.entity_manager"]
Then just add a constructor to your class:
protected $em;
public function __construct($em)
{
$this->em = $em
}

Related

2 Deprecations in my Symfony 3 Project

I have 2 deprecations in my Symfony 3 project when try to define a custom service in service.yml that I would like to solve but I don't get the way...
This my code FollowingExtension.php
<?php
namespace AppBundle\Twig;
use Symfony\Bridge\Doctrine\RegistryInterface;
class FollowingExtension extends \Twig_Extension {
protected $doctrine;
public function __construct(RegistryInterface $doctrine) {
$this->doctrine = $doctrine;
}
public function getFilters() {
return array(
new \Twig_SimpleFilter('following', array($this, 'followingFilter'))
);
}
public function followingFilter($user, $followed){
$following_repo = $this->doctrine->getRepository('BackendBundle:Following');
$user_following = $following_repo->findOneBy(array(
"user" => $user,
"followed" => $followed
));
if(!empty($user_following) && is_object($user_following)){
$result = true;
}else{
$result = false;
}
return $result;
}
public function getName() {
return 'following_extension';
}
}
And this is my services.yml:
following.twig_extension:
class: AppBundle\Twig\FollowingExtension
public: false
arguments:
$doctrine: "#doctrine"
tags:
- { name: twig.extension }
I would appreciate the help they gave me in trying to solve my problem.
First problem solution
It looks like because of registering services with duplicate name, as declared in your class:
`return 'following_extension';`
Make sure that you only have one twig service named following_extension. If you are sure that only one twig service named following_extension, you probably register more than one service using that class.
Second problem solution
Replace
`use Symfony\Bridge\Doctrine\RegistryInterface;`
with
`use Doctrine\Common\Persistence\ManagerInterface;`
and also replace
`public function __construct(RegistryInterface $doctrine) {`
with
`public function __construct(ManagerInterface $doctrine) {`
Finally solved the problem and i want share the info...
Reading the documentation of Symfony found this How to Create Service Aliases and Mark Services as Private and them I declared my service this way:
in service.yml:
following.twig_extension: '#AppBundle\Twig\FollowingExtension'
and FollowingExtension.php
<?php
namespace AppBundle\Twig;
use Doctrine\Common\Persistence\ManagerRegistry;
class FollowingExtension extends \Twig_Extension {
private $managerRegistry;
public function __construct(ManagerRegistry $managerRegistry) {
$this->managerRegistry = $managerRegistry;
}
public function getFilters() {
return array(
new \Twig_SimpleFilter('following', array($this, 'followingFilter'))
);
}
public function followingFilter($user, $followed){
$following_repo = $this->managerRegistry->getRepository('BackendBundle:Following');
$user_following = $following_repo->findOneBy(array(
"user" => $user,
"followed" => $followed
));
if(!empty($user_following) && is_object($user_following)){
$result = true;
}else{
$result = false;
}
return $result;
}
}
Thanks for helping me and I'm sorry if my english is bad.

How pass 'templating' component for service as argument?

I have a method in 'DynamicList' service that should return a select filled with dynamic data, but i'm getting "circular reference":
YML:
parameters:
my.dynamic_list.class: My\DynamicListBundle\Service\DynamicList
services:
my.dynamic_list:
class: %my.dynamic_list.class%
arguments: ['#doctrine.orm.default_entity_manager','#templating']
Class:
<?php
namespace My\DynamicListBundle\Service;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class DynamicList
{
private $em;
private $templating;
public function __construct(
EntityManager $em,
EngineInterface $templating
) {
$this->em = $em;
$this->templating = $templating;
}
public function getSelect($slug)
{
$dynamic_list = $this->em
->getRepository('MyDynamicListBundle:DynamicList')
->findOneBy(array(
"slug" => $slug
));
return $this->templating->render('MyComponentsCoreBundle::Templates/DynamicList/combo.html.twig', array(
'dl' => $dynamic_list
));
}
}
I guess i don't need to put here the twig content: the problema occurs before.
Last, the error i'm getting:
Circular reference detected for service "my.dynamic_list", path: "my.dynamic_list -> templating -> twig". (500 Internal Server Error - ServiceCircularReferenceException)
What's the proper way to get templating component working in my service?
Well, I found a workaround but I don't if is the best way:
<?php
namespace My\DynamicListBundle\Service;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class DynamicList
{
private $em;
private $templating;
public function __construct(
EntityManager $em
) {
$this->em = $em;
}
public function init(
EngineInterface $templating
) {
$this->templating = $templating;
}
public function getSelect($slug)
{
$dynamic_list = $this->em
->getRepository('MyDynamicListBundle:DynamicList')
->findOneBy(array(
"slug" => $slug
));
return $this->templating->render('MyComponentsCoreBundle::Templates/DynamicList/combo.html.twig', array(
'dl' => $dynamic_list
));
}
}
So, in controller, I call 'init()' to pass 'templating':
$dl_service = $this->get('my.dynamic_list');
$dl_service->init($this->container->get('templating'));

FatalErrorException: Error: Call to a member function has() on a non-object symfony

I am using a symfony controller as a service.But when I call doctrine manager in the controller it gives the error FatalErrorException: Error: Call to a member function has() on a non-object.
Here is my controller:
namespace Acme\StoreBundle\Controller;
use Doctrine\ORM\EntityManager;
class ServiceController extends Controller {
/**
*
* #var EntityManager
*/
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
}
and my services.yml is like:
services:
service_controller:
class: Acme\StoreBundle\Controller\ServiceController
arguments: ["#doctrine.orm.entity_manager"]
I am calling the entity manager in an other controller which DbController:
<?php
public function users()
{
$query = $this->em->createQuery('select u from AcmeStoreBundle:User u');
$user = $query->getResult();
}
You can get the EntityManager in ServiceController likeļ¼š
$em = $this->getDoctrine()->getManager();
so the following codes make no sense:
service_controller:
class: Acme\StoreBundle\Controller\ServiceController
arguments: ["#doctrine.orm.entity_manager"]
And i really want to see your DbController codes, can you show that?
My DbController is like:
<?php
namespace Acme\StoreBundle\Controller;
use Acme\StoreBundle\Entity\UserCategoryTag;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DbController extends Controller
{
//Suppose you want get all users you can do some like this..
public function Users() {
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('AcmeStoreBundle:User');
$user = $repository->findAll();
}
}
You can also get using per-execute method like follow:
1] Create new listener class for pre-execute method
namespace Acme\Listener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
/**
* Acme\Listener\ControllerListener
*/
class ControllerListener
{
/**
* On Core Controller this is used to set pre execute
*
* #param GetResponseEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
$_controller = $event->getController();
if (isset($_controller[0])) {
$controller = $_controller[0];
if (method_exists($controller, 'preExecute')) {
$controller->preExecute();
}
}
}
}
}
2] configure listener in your config file app/config/config.yml
services:
controller.pre_execute_listener:
class: Acme\Listener\ControllerListener
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }
3] controller file
namespace Acme\StoreBundle\Controller;
use Doctrine\ORM\EntityManager;
class ServiceController extends Controller {
public function preExecute()
{
$this->em = $this->getDoctrine()->getEntityManager();
}
}
4] your function
<?php
public function users()
{
$query = $this->em->createQuery('select u from AcmeStoreBundle:User u');
$user = $query->getResult();
}
I solved this by trying a lot of things.
Here is the solution for this :
You have to use your controller as service.I used TagClass Controller as a service.Here is my controller code:
<?php
namespace Acme\StoreBundle\Controller;
class TagClassController extends Controller
{
public $em;
public function __construct(Entity Manager $em)
{
$this->em = $em;
}
public function ParseWebsite($categoryid){
}
}
?>
For using this you have to define the controller as service in your services.yml like this:
parameters:
acme.controller.tagclass.class: Acme\StoreBundle\Controller\TagClassController
services:
acme.controller.tagclass:
class: "%acme.controller.tagclass.class%"
arguments: [ #doctrine.orm.entity_manager ]
And you can call any method with in TagClass like this:
$this->forward('acme.controller.tagclass:ParseWebsite',array($categoryid));

How to get Request object inside a Twig Extension in Symfony?

How can one access the Request object inside Twig Extension?
namespace Acme\Bundle\Twig;
use Twig_SimpleFunction;
class MyClass extends \Twig_Extension
{
public function getFunctions()
{
return array(
new Twig_SimpleFunction('xyz', function($param) {
/// here
$request = $this->getRequestObject();
})
);
}
public function getName() {
return "xyz";
}
}
As requested in the comments, here's the prefered way of injecting a request into any service. It works with Symfony >= 2.4.
Injecting the request and putting our service in the request scope is no longer recommended. We should use the request stack instead.
namespace AppBundle\Twig;
use Symfony\Component\HttpFoundation\RequestStack;
class MyClass extends \Twig_Extension
{
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function getFunctions()
{
$requestStack = $this->requestStack;
return array(
new \Twig_SimpleFunction('xyz', function($param) use ($requestStack) {
$request = $requestStack->getCurrentRequest();
})
);
}
public function getName()
{
return "xyz";
}
}
app/config/services.yml
app.twig_extension:
class: AppBundle\Twig\MyExtension
arguments:
- '#request_stack'
tags:
- { name: twig.extension }
Docs:
the request stack API
the request stack announcement
Register your extension as a service and give it the container service:
# services.yml
services:
sybio.twig_extension:
class: %sybio.twig_extension.class%
arguments:
- #service_container
tags:
- { name: twig.extension, priority: 255 }
Then retrieve the container by your (twig extension) class constructor and then the request:
<?php
// Your class file:
// ...
class MyClass extends \Twig_Extension
{
/**
* #var ContainerInterface
*/
protected $container;
/**
* #var Request
*/
protected $request;
/**
* Constructor
*
* #param ContainerInterface $container
*/
public function __construct($container)
{
$this->container = $container;
if ($this->container->isScopeActive('request')) {
$this->request = $this->container->get('request');
}
}
// ...
Note that testing the scope is usefull because there is no request when running console command, it avoids warnings.
That's it, you are able to use the request !
I would suggest setting 'needs_environment' => true for your Twig_SimpleFunction, which then will add \Twig_Environment as first argument of your function. Then in your function you can find the request like this:
$request = $twig->getGlobals()['app']->getRequest();
So the whole function will look like this:
...
public function getFunctions() {
return [
new \Twig_SimpleFunction('xyz', function(\Twig_Environment $env) {
$request = $twig->getGlobals()['app']->getRequest();
}, [
'needs_environment' => true,
]),
];
}
...

Pass path parameters automatically

I'm building a site where the user can choose a country, state and city he wants.
Once he selects these parameters he goes to a page like this: en.example.com/spain/madrid/madrid/
The problem is, every time I want to build a new url, I must pass these 3 variables and I was wondering if I could do something to make them just like the _locale variable which symfony itself passes it to the parameters.
Thanks
After searching more I found this post: http://blog.viison.com/post/15619033835/symfony2-twig-extension-switch-locale-current-route
I just used the idea and made the changes I needed and this is the final code for my extension
<?php
namespace Comehoy\CoreBundle\Twig\Extension;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernel;
class PathExtension extends \Twig_Extension
{
private $request;
private $router;
public function __construct(Router $router) {
$this->router = $router;
}
public function onKernelRequest(GetResponseEvent $event) {
if ($event->getRequestType() === HttpKernel::MASTER_REQUEST) {
$this->request = $event->getRequest();
}
}
public function getFunctions()
{
return array(
'l10n_path' => new \Twig_Function_Method($this, 'getPath')
);
}
public function getPath($name, $parameters = array())
{
$parameters = array_merge($parameters, [
'country' => $this->request->get('country'),
'state' => $this->request->get('state'),
'city' => $this->request->get('city'),
]);
return $this->generator->generate($name, $parameters, false);
}
public function getName()
{
return 'twig_my_path_extension';
}
}
And as for the configuration its the same as the post
services:
twig.localized_route_extension:
class: Acme\CoreBundle\Twig\PathExtension
tags:
- { name: twig.extension }
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
arguments: [#router]
And for the routes that I use country, state and the city I put them in the prefix to avoid repeating them in each route.
acme_core:
resource: "#AcmeCoreBundle/Controller/"
type: annotation
prefix: /{country}/{state}/{city}
Hope it helps someone else.

Resources