1

I created my first own service in Symfony :

// src/Service/PagesGenerator.php 

namespace App\Service;

class PagesGenerator
{
    public function getPages()
    {

      $page = $this->getDoctrine()->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);

        $messages = [
            'You did it! You updated the system! Amazing!',
            'That was one of the coolest updates I\'ve seen all day!',
            'Great work! Keep going!',
        ];

        $index = array_rand($messages);

        return $messages[$index];
    }
}

But I get the error message:

Attempted to call an undefined method named "getDoctrine" of class "App\Service\PagesGenerator".

I tried then to add in my services.yaml:

PagesGenerator:
    class: %PagesGenerator.class%
    arguments:
      - "@doctrine.orm.entity_manager"

But then I get the error message:

The file "/Users/work/project/config/services.yaml" does not contain valid YAML in /Users/work/project/config/services.yaml (which is loaded in resource "/Users/work/project/config/services.yaml").

tereško
  • 58,060
  • 25
  • 98
  • 150
peace_love
  • 6,229
  • 11
  • 69
  • 157
  • Symfony is working with the magic pattern called Dependency Injection. Instead of giving any argument to your service in `services.yaml`, call `__construct(EntityManagerInterface $em)` in your service and let Symfony inject your entity manager. It's much clearer in my opinion. – GasKa Mar 05 '19 at 10:06
  • @GasKa Thank you very much. This sounds really good. Can you give an example. I tried to put this line into my service but I get the error `syntax error, unexpected '$em' ` – peace_love Mar 05 '19 at 10:09
  • I think you used `$em` instead of `$this->em`. Also, you have to declare this property for your service before `__construct()`. – GasKa Mar 05 '19 at 10:10
  • @GasKa Ok, I am not exactly knowing how to do it, but I try and let you know if it worked – peace_love Mar 05 '19 at 10:12
  • I'll make a reply instead of comment for that. Check it out in few minutes. – GasKa Mar 05 '19 at 10:13
  • 1
    As I said my answer in your previous question: read the documentation. Using Autowiring is part of the Symfony Best Practices. – Stephan Vierkant Mar 05 '19 at 12:04
  • 1
    But not reading the documentation? Again: use autowiring. – Stephan Vierkant Mar 05 '19 at 12:09
  • @StephanVierkant Yes but first I needed to figure out where to create the class. So I did a tutorial and wanted to get the tutorial work and understand, before I go to the next step understand "autowiring" – peace_love Mar 05 '19 at 12:11

3 Answers3

11

So, in comments I was saying that is better to let Symfony doing his job and autowiring EntityManager. This is what you should do. Also, can you tell us what Symfony version are you using and if autowiring is enabled (check services.yaml for that)?

<?php

namespace App\Service;

use Doctrine\ORM\EntityManagerInterface;

class PagesGenerator
{
    public function __construct(EntityManagerInterface $em) {
        $this->em = $em;
    }

    public function getPages()
    {

      $page = $this->em->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);

        $messages = [
            'You did it! You updated the system! Amazing!',
            'That was one of the coolest updates I\'ve seen all day!',
            'Great work! Keep going!',
        ];

        $index = array_rand($messages);

        return $messages[$index];
    }
}
GasKa
  • 663
  • 5
  • 25
  • 1
    That sounds about right but what'd happen if i need to call another Manager to get my Repository? since EntityManagerInterface doesn't have a getManager() attribute i can only call the repository from the 'default'. If i try to do a $this->getDoctrine() from a Service i get an error :: Call to a member function has() on null – SpicyTacos23 Dec 21 '20 at 16:29
3

With Symfony 4 and the new autowiring you can easily inject certain number of class

To find out, which classes/interface you can use for autowiring, use this command:

bin/console   debug:autowiring 

We are going to use this one :

Doctrine\ORM\EntityManagerInterface (doctrine.orm.default_entity_manager)

So let's make it, add this just before getPages function

/**
 * @var EntityManagerInterface
 */
private $em;

public function __construct(EntityManagerInterface $em)
{
    $this->em = $em;
}

Then you can use it like this:

  $page = $this->em->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);

Hope it helps !

1

make sure you use proper indent using "spaces" for YAML.

A YAML file use spaces as indentation, you can use 2 or 4 spaces for indentation, but no tab read more about this

Before symfony 3.3

for example we have service sms_manager in AppBundle/FrontEndBundle/Services

services:
    AppBundle.sms_manager:
        class: AppBundle\FrontEndBundle\Services\SmsManager
        arguments: [ '@service_container' ,'@doctrine.orm.entity_manager' ]

then your service can receive your arguments in constructor

<?php

namespace AppBundle\FrontEndBundle\Services;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class SmsManager {
    private $container;
    private $DM;

    public function __construct( Container $container, \Doctrine\ORM\EntityManager $DM ) 
    {
        $this->container = $container;
        $this->DM        = $DM;
    }

    /**
    * @return \Doctrine\ORM\EntityManager
    */

    public function getDoctrine() {
      return $this->DM;
    }

}

With Symfony 3.3 or more,

Is there a way to inject EntityManager into a service

use Doctrine\ORM\EntityManagerInterface

class PagesGenerator
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    // ...
}
Noman
  • 4,088
  • 1
  • 21
  • 36