Non-existent service error since symfony 3.3 - php

I had 2 working services at my symfony 3.2.(8?) project and had to up to 3.3 (currently 3.3.2). One of my services is working just fine, and the second one is giving me error:
services.yml
parameters:
#parameter_name: value
services:
_defaults:
autowire: true
autoconfigure: true
public: false
AppBundle\:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository}'
list_brands:
class: AppBundle\Service\ListBrands
arguments: [ '#doctrine.orm.entity_manager' ]
calls:
- method: getBrands
picture_upload:
class: AppBundle\Service\UploadPicture
arguments: ['#kernel']
src\AppBundle\Service\UploadPicture.php
<?php
namespace AppBundle\Service;
use DateTime;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpKernel\Kernel;
class UploadPicture
{
protected $kernel;
public function __construct(Kernel $kernel)
{
$this->kernel = $kernel;
}
public function uploadPicture($object, string $oldPic, string $path)
{
/** #var UploadedFile $image */
$image = $object->getImage();
$time = new DateTime('now');
if ($image) {
$imgPath = '/../web/' . $path;
$filename = $time->format('d-m-Y-s') . md5($time->format('s')) . uniqid();
$image->move($this->kernel->getRootDir() . $imgPath,$filename . '.png');
$object->setImage($path . $filename . '.png');
} else {
$object->setImage($oldPic);
}
}
}
Error: You have requested a non-existent service "picture_upload".
Calling it like this: $uploadService = $this->get('picture_upload');

You have not written how you inject / call your service, but calling $this->get() sounds like a call from within a controller. I guess this is related to the new change in Symfony and your default service config of the public attribute.
Please check the following commented lines in your configuration:
# services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false # here you are setting all service per default to be private
AppBundle\:
resource: '../../src/AppBundle/*'
exclude: '../../src/AppBundle/{Entity,Repository}'
list_brands:
class: AppBundle\Service\ListBrands
arguments: [ '#doctrine.orm.entity_manager' ]
calls:
- method: getBrands
picture_upload:
class: AppBundle\Service\UploadPicture
arguments: ['#kernel']
public: true # you need to explicitly set the service to public
You need to mark the service as public, either per default (not recommended) or explicitly in the service definition.

Related

Symfony3.4: Attempted to call an undefined method named "getParameter" of class "Symfony\Component\DependencyInjection\ServiceLocator"

In Symfony3.4, the following error occurred while supporting automatic wiring.
The following error occurs even if the container is removed, just changing the class.
I changed the controller to an abstract controller due to another error, so I want to use the abstract controller as much as possible.
Is there anything I have forgotten?
https://symfony.com/doc/3.4/service_container/3.3-di-changes.html
Error
Attempted to call an undefined method named "getParameter" of class "Symfony\Component\DependencyInjection\ServiceLocator".
Controller.php
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class DefaultController extends AbstractController
{
/**
* #param KeepRequestService $keepRequestService
* #return array
*/
private function getKeepRequestSummary(KeepRequestService $keepRequestService): array
{
$summary = array();
//Error line
foreach (array_keys($this->container->getParameter('keep_request_status')) as $status) {
$params = array('status' => $status);
$summary[$status] = $keepRequestService->countKeepRequestBySearchParams($params);
}
return $summary;
}
services.yml
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../../src/*'
exclude: '../../src/{Ahi/Sp/AdminBundle/Model/Entity, Ahi/Sp/AdminBundle/Model/Repository, Ahi/Sp/AdminBundle/Resources/public/uploadify, Ahi/Sp/AdminBundle/Ahi/Sp/PublicBundle/ }'
App\Ahi\Sp\AdminBundle\Controller\:
resource: '../../src/Ahi/Sp/AdminBundle/Controller'
public: true
tags: ['controller.service_arguments']
As Vyctorya advised, I modified the code as below and the code disappeared.
Controller.php
/**
* #var array
*/
private $keepRequestStatus;
public function __construct(array $keepRequestStatus)
{
$this->keepRequestStatus = $keepRequestStatus;
}
private function getKeepRequestSummary(KeepRequestService $keepRequestService)
{
$summary = array();
foreach (array_keys($this->keepRequestStatus) as $status) {
$params = array('status' => $status);
$summary[$status] = $keepRequestService->countKeepRequestBySearchParams($params);
}
return $summary;
}
services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
bind:
$keepRequestStatus: '%keep_request_status%'

How to pass dynamic values to container in Symfony 5

How passing a dynamic variable from controller to a service? I want manage some istance in the constructor of my service that depend by json value. My service take two parameters in the construct: a service and a variable with the JSON.
For the first one, i have passed it directly in the service.yaml. For the second one, i have some difficult.
In the controller, i get from a API the JSON. But this json it can be null.
class IndexController extends AbstractController
{
/**
* #Route("/converter-hl7", name="converter", methods={"POST"})
*/
public function index(Request $request, $myjson = null) {
$myjson = $request->getContent();
global $kernel;
$converter = $kernel->getContainer()->get('app.converter');
$xml = $converter->outputXML();
$response = new Response($xml);
$response->headers->set('Content-Type', 'xml');
return $response;
}
I stock the JSON in my .env file, MYJSON=null.
This is my service.yaml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '../src/Tests/'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
# explicitly configure the service
app.error:
class: App\Service\Error
public: true
autowire: true
app.converter:
class: App\Service\ConverterHl7Refacto
public: true
autowire: true
arguments:
$error: '#app.error'
$json: '%env(MYJSON)'
So, in my service called ConverterHl7Refacto.php, i have the two parameters in the constructor. I would like manage the istances if the json is empty or non. If i do a dd() of $json, i get '%env(MYJSON)' instead JSON. Why?
class ConverterHl7Refacto
{
private $ricetta;
private $identificativiDocumento;
private $codiceDocumento;
private $infoDocumento;
private $assistiti;
private $partecipanti;
private $relatedDoc;
private $structuredBody;
private $root;
private $error;
public function __construct(string $json,Error $error) {
$this->error = $error;
if ($json){
$this->ricetta = new Ricetta(json_decode($json));
$this->root = new Root();
$this->identificativiDocumento = new Identificativi();
$this->codiceDocumento = new CodiceDocumento($this->ricetta);
$this->infoDocumento = new InfoDocumento($this->ricetta);
$this->assistiti = new Assistiti($this->ricetta);
$this->partecipanti = new Partecipanti($this->ricetta);
$this->relatedDoc = new RelatedDocument($this->ricetta);
$this->structuredBody = new StructuredBody($this->ricetta);
}
}
Nothing particularly tricky about the factory concept. A factory is basically used to create an instance of a given type. I did not test the following code so apologies for typos:
class Error {}
class Converter {
public function __construct(string $json, Error $error)
{
// Whatever
...
class ConverterFactory {
private $error;
public function __construct(Error $error) {
$this->error = $error;
}
public function create(string $json) : Converter {
return new Converter($json,$this->error);
}
}
class MyController {
public function action(ConverterFactory $converterFactory)
{
$json = $request->getContent();
$converter = $converterFactory->create($json);
You will need to exclude your Converter class from autowire in your services.yaml file. But that should be all you need. No need to explicitly define things like app.converter as autowire will take care of all that.

Autowiring problem with parameter injection in Symfony 5

I'm having troubles trying to retrieve a manager from a controller in Symfony 5.
I've got this MailerManager in src/Manager/MailerManager.php:
<?php
namespace App\Manager;
use App\Client\MailjetClient;
class MailerManager {
private $mailjetClient;
function __construct(MailjetClient $mailjetClient) {
$this->setMailjetClient($mailjetClient);
}
function send($data) {
}
function getMailjetClient() {
return $this->mailjetClient;
}
private function setMailjetClient($mailjetClient) {
$this->mailjetClient = $mailjetClient;
}
}
This manager needs to inject src/Client/MailjetClient.php in order to work, that has got this code:
<?php
namespace App\Client;
use \Mailjet\Resources;
class MailjetClient {
private $client;
function __construct(string $apikey, string $apisecret) {
$this->setClient($apikey, $apisecret);
}
function getClient() {
return $this->client;
}
function setClient($apikey, $apisecret) {
$this->client = new \Mailjet\Client($apikey, $apisecret);
}
}
This is just a wrapper for the mailjet sdk installed via composer, that needs to be feeded with different $apikey and $apisecret depending on the environment, for what I'm using parameters through services.yaml file, where I also have got autowiring enabled and service definitions for both MailjetClient and MailerManager:
parameters:
rabbitmq:
host: '%env(RABBITMQ_HOST)%'
port: '%env(RABBITMQ_PORT)%'
user: '%env(RABBITMQ_USER)%'
pwd: '%env(RABBITMQ_PWD)%'
mailjet:
apikey: '%env(MAILJET_APIKEY)%'
apisecret: '%env(MAILJET_APISECRET)%'
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
App\Client\MailjetClient\:
resource: '../src/Client/MailjetClient.php'
arguments:
$apikey: '%mailjet.host%'
$apisecret: '%mailjet.port%'
App\Manager\MailerManager\:
resource: '../src/Manager/MailerManager.php'
arguments:
$mailjetClient: '#client.mailjet'
The problem I'm having is that I'm getting this error: Cannot autowire service "App\Client\MailjetClient": argument "$apikey" of method "__construct()" is type-hinted "string", you should configure its value explicitly. when I try to inject the MailManager in the src/Controller/MailerController.php controller:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Manager\MailerManager;
class MailerController extends AbstractController
{
/**
* #Route("/compose", name="compose")
*/
public function compose(MailerManager $mailerManager)
{
dump($mailerManager);die();
}
}
}
What could posibbly be wrong? I'm coming from Symfony 2, and this parameter injection was something standard that used to work like a charm, now I'm totally confused about how to mix the autowiring with the service manual definition.
I had a total disaster on the services.yml side, thanks to u_mulder and Tejas Gosai hints I could finally put this to work. I had a few type errors on the parameters I was injecting, the MailManager.php specific declaration was not needed, and my client namespaces should not end with \ ad u_mulder suggested.
Finally, with this services.yml it works:
parameters:
rabbitmq.host: '%env(RABBITMQ_HOST)%'
rabbitmq.port: '%env(RABBITMQ_PORT)%'
rabbitmq.user: '%env(RABBITMQ_USER)%'
rabbitmq.pwd: '%env(RABBITMQ_PWD)%'
mailjet.apikey: '%env(MAILJET_APIKEY)%'
mailjet.apisecret: '%env(MAILJET_APISECRET)%'
services:
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
App\Client\MailjetClient:
arguments:
$apikey: '%mailjet.apikey%'
$apisecret: '%mailjet.apisecret%'
App\Client\RabbitClient:
arguments: ['%rabbitmq.host%','%rabbitmq.port%','%rabbitmq.user%','%rabbitmq.pwd%']

Symfony event subscriber not working even service is defined

I have an event subscriber:
namespace App\EventListener;
use App\Entity\Token;
use App\Model\EncryptUtils;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\Common\EventSubscriber;
class DatabaseSubscriber implements EventSubscriber
{
public function getSubscribedEvents()
{
return array(
'prePersist'
);
}
public function prePersist(LifecycleEventArgs $args)
{
$entity = $args->getObject();
if ($entity instanceof Token) {
$enityt->setCreatedAt(new \DateTime());
}
}
}
And I've declared the service in services.yaml:
parameters:
locale: 'en'
services:
App\EventListener\DatabaseSubscriber:
tags:
- { name: doctrine.event_subscriber, connection: default }
_defaults:
autowire: true
autoconfigure: true
public: false
bind:
$appSecret: '%kernel.secret%'
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
But there's no way to get it working. I've also tried with an event listener but nothing happens
You should declare your service after all the default configuration because if not, the default configuration is overriding yours.
So your services.yaml file should be:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
bind:
$appSecret: '%kernel.secret%'
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
App\EventListener\DatabaseSubscriber:
tags:
- { name: doctrine.event_subscriber, connection: default }

Symfony2 components, class instances

Question is why
$config = array(__DIR__ . '/app/config');
$locator = new Symfony\Component\Config\FileLocator($config);
$loader = new Symfony\Component\Routing\Loader\YamlFileLoader($locator);
$routes_collection = $loader->load('routes.yml');
Here $routes_collection is an instance of Symfony\Component\Routing\RouteCollection, and this code works fine.
And here
# config.yml
file_locator:
class: Symfony\Component\Config\FileLocator
arguments: ['%app_root%/app/config']
route_collection:
class: Symfony\Component\Routing\Loader\YamlFileLoader
arguments: ["#file_locator"]
calls:
- [load, ['routes.yml']]
#app.php
$routes_collection = $container->get('route_collection')
$routes_collection is an instance of Symfony\Component\Routing\Loader\YamlFileLoader and if i use it with Symfony\Component\Routing\Matcher\UrlMatcher am getting:
Argument 1 passed to Symfony\Component\Routing\Matcher\UrlMatcher::__construct() must be an instance of Symfony\Component\Routing\RouteCollection, instance of Symfony\Component\Routing\Loader\YamlFileLoader given.
Update
#Pazi ツ, but how to be if i want to use route_collection in matcher
matcher:
class: Symfony\Component\Routing\Matcher\UrlMatcher
arguments: ["#route_collection", "#context"]
If you want to take route_collection via config you need to define route_collection yaml_file_loader as the factory service of route_collection:
# config.yml
file_locator:
class: Symfony\Component\Config\FileLocator
arguments: ['%app_root%/app/config']
yaml_file_loader:
class: Symfony\Copmonent\Routing\Loader\YamlFileLoader
arguments: [ "#file_locator" ]
route_collection:
class: Symfony\Component\Routing\RouteCollection
factory_service: yaml_file_loader
factory_method: load
arguments: [ 'routes.yml' ]
This way you can do
$routes_collection = $container->get('route_collection');
Of course your service is an instance of YamlFileLoader because you configured this in the class attribute. The return value of the methods calls doesn't influence the instance type. You have to call the method in php, if you want to get the return value.
# config.yml
file_locator:
class: Symfony\Component\Config\FileLocator
arguments: ['%app_root%/app/config']
yaml_file_loader:
class: Symfony\Component\Routing\Loader\YamlFileLoader
arguments: ["#file_locator"]
#app.php
$routes_collection = $container->get('yaml_file_loader')->load('routes.yml');

Categories