symfony6 - defining and using services.yaml in third part bundle - symfony

I'm making simple "MyCoreBundle" (MystertyCoreBundle) using symfony6.1 how to make bundle's doc.
I defined my bundle class vendor/mysterty/core-bundle/CoreBundle.class
<?php
namespace Mysterty\CoreBundle;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
class MystertyCoreBundle extends AbstractBundle
{
}
I defined some parameters and configuration in vendor/mysterty/core-bundle/config/services.yaml as defaults :
services:
Mysterty\CoreBundle\Controller\CoreController:
public: true
calls:
- method: setContainer
arguments: ["#service_container"]
parameters:
app.admin_email: "mymailATserver.com"
Then I made simple controller in vendor/mysterty/core-bundle/src/Controller/CoreController.php:
<?php
namespace Mysterty\CoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
class CoreController extends AbstractController
{
#[Route('/', name: 'mty_default')]
public function indexNoLocale(): Response
{
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
$supportedLangs = explode('|', $this->getParameter('app.supported_locales'));
$lang = in_array($lang, $supportedLangs) ? $lang : $supportedLangs[0];
return $this->redirectToRoute('mty_home', ['_locale' => $lang]);
}
Finally, i added the bundle's routes to \config\routes.yaml
mysterty_core:
resource: "../vendor/mysterty/core-bundle/src/Controller/CoreController.php"
type: annotation
prefix: /
Here is the error i have on http://127.0.0.1:8000/ :
"Mysterty\CoreBundle\Controller\CoreController" has no container set, did you forget to define it as a service subscriber?
I try to make a shared bundle with default actions and components for all my symfony projects.
Solution (thx to helpers)
define loadExtension function in MyOwnBundle.php :
<?php
namespace MyOwn\MyOwnBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
class MyOwnBundle extends AbstractBundle
{
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{
// load an XML, PHP or Yaml file
$container->import('../config/services.yaml');
}
}

It looks like Symfiony could not autoconfigure your controller. Try adding the #[AsController] attribute to your controller classes or add autoconfigure: true to your controller service definition in your services.yaml

Related

Call function in controller using service symfony 5

I tried to call a function in a controller using service:
#BookManager.php
<?php
namespace App\Service;
use App\Entity\BookContent;
use Doctrine\ORM\EntityManagerInterface;
class BookManager
{
protected $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function getBookTitle(string $page){
return $this->entityManager->getRepository(BookContent::class)
>findOneBy(["page"=>$page])->getTitle();
}
In service.yml
....
services:
book.manager:
class: App\Service\BookManager
arguments: ['#doctrine.orm.entity_manager']
public: true
Finally I call it in Controller ;
$pageName = $this->container->get('request_stack')->getMasterRequest()->get('_route');
$bookTitle = $this->container->get('book.manager')->getBookTitle($pageName);
But I get this error
Service "book.manager" not found: even though it exists in the app's container, the container inside "App\Controller\HomeController" is a smaller service locator that only knows about the "doctrine", "form.factory", "http_kernel", "parameter_bag", "request_stack", "router", "security.authorization_checker", "security.csrf.token_manager", "security.token_storage", "serializer", "session" and "twig" services. Try using dependency injection instead.
Any idea?
EDIT
it's work when I use dependency injection but only when I do query with $id
$this->entityManager->getRepository(BookContent::class)-
>findOneById(["id"=>$id])->getTitle();
when I do it with findOneBy(["page"=>$page]) I get this error:
Impossible to access an attribute ("title") on a null variable.
By default Symfony 5 will autowire/auto configure your services. You can remove the book.manager from your service.yaml.
You can then use dependency injection in your controllers to access your services, like this for example:
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Service\BookManager; //<-- Add use
class YourController extends AbstractController
{
/**
* #Route("/", name="home")
*/
public function index(Request $request, BookManager $bookManager): Response
{
$pageName = $request->attributes->get('_route');
$bookTitle = $bookManager->getBookTitle($pageName);
return ...
}
}

Cannot inject Templating on Symfony 4 Service

I have the following class:
EmailNotification
namespace App\Component\Notification\RealTimeNotification;
use Symfony\Bridge\Twig\TwigEngine;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use App\Component\Notification\NotificationInterface;
class EmailNotification implements NotificationInterface
{
private $logNotification;
public function __construct(LogNotification $logNotification, \Swift_Mailer $mailer, EngineInterface $twigEngine)
{
$this->logNotification = $logNotification;
}
public function send(array $options): void
{
$this->logNotification->send($options);
dump('Sent to email');
}
}
I have the following service definition on my yml:
app.email_notification:
class: App\Component\Notification\RealTimeNotification\EmailNotification
decorates: app.log_notification
decoration_inner_name: app.log_notification.inner
arguments: ['#app.log_notification.inner', '#mailer', '#templating']
However, when i tried to run my app it throws an Exception saying:
Cannot autowire service
"App\Component\Notification\RealTimeNotification\EmailNotification":
argument "$twigEngine" of method "__construct()" has type
"Symfony\Bundle\FrameworkBundle\Templating\EngineInterface" but this
class was not found.
Why is that so?
Thanks!
You have to install symfony/templating
composer require symfony/templating
change a little bit config/packages/framework.yaml
framework:
templating:
engines:
- twig
I managed to do it with Twig Environment and HTTP Response
<?php
namespace App\Controller;
use Twig\Environment;
use Symfony\Component\HttpFoundation\Response;
class MyClass
{
private $twig;
public function __construct(Environment $twig)
{
$this->twig = $twig;
}
public function renderTemplateAction($msg)
{
return new Response($this->twig->render('myTemplate.html.twig'));
}
}
Most likely you don't have Templating included in your project, in Symfony 4 you have to require it explicitly:
composer require symfony/templating

how make services in symfony3

i have this controller
namespace InicioBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use EntidadesBundle\Entity\Usuarios;
use Symfony\Component\HttpFoundation\Session\Session;
class DefaultController extends Controller
{
private $session;
public function __construct(){
$this->session = new Session();
}
.....
public function ver_rol($rol){
if($this->sacarRol() === $rol){
return true;
}else{
return false;
}
}
}
and in the services.yml , i got this:
parameters:
#parameter_name: value
services:
app.rolSession:
class: InicioBundle\Controller\DefaultController
arguments: ["i dont know how get paramets"]
the problem is that it doesnt work, symfony return an error FileLoaderLoadException, that the services.yml does not caontain valid YAML
There is a space before parameters: in your services.yml file, maybe remove that and your yaml should be valid.
Also if you are passing no arguments to constructor you can just delete arguments: ["null"]
One more thing, IIRC you need to add FQCN as class name, so class: InicioBundle\Controller\Default => class: InicioBundle\Controller\DefaultController
While we are at the subject, you can type hint Request in your action and use it to getSession() or maybe inject #session service to your controller

How to have a global variable coming from db in symfony template?

How can I have a global variable in symfony template?
I did read this
but I prefer to fetch parameter from database, I think this service will be loaded on startup before it can fetch anything from db. Is it possible to do a trick to do so?
EDIT: Update in 2019 with Symfony 3.4+ syntax.
Create a Twig extension where you inject the Entity Manager:
Fuz/AppBundle/Twig/Extension/DatabaseGlobalsExtension.php
<?php
namespace Fuz\AppBundle\Twig\Extension;
use Doctrine\ORM\EntityManager;
use Twig\Extension\AbstractExtension;
use Twig\Extension\GlobalsInterface;
class DatabaseGlobalsExtension extends AbstractExtension implements GlobalsInterface
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function getGlobals()
{
return [
'myVariable' => $this->em->getRepository(FuzAppBundle\Entity::class)->getSomeData(),
];
}
}
Register your extension in your Fuz/AppBundle/Resources/config/services.yml:
services:
_defaults:
autowire: true
autoconfigure: true
Fuz\AppBundle\Twig\Extension\DatabaseGlobalsExtension: ~
Now you can do the requests you want using the entity manager.
Don't forget to replace paths and namespaces to match with your application.
As of this day, the class signature has changed. You must implement \ Twig_Extension_GlobalsInterface, without it, your globals won't show up.
class MyTwigExtension extends \Twig_Extension implements Twig_Extension_GlobalsInterface
{ }
Bye!
you can register a twig extension
services:
twig_extension:
class: Acme\DemoBundle\Extension\TwigExtension
arguments: [#doctrine]
tags:
- { name: twig.extension }
And then in the TwigExtension you can do as follows:
class TwigExtension extends \Twig_Extension
{
public function getGlobals() {
return array(
// your key => values to make global
);
}
}
So you could get a value from the database in this TwigExtension and pass it to the template with the getGlobals() function
Stay away from global variables.
Instead make a custom twig extension then inject the database connection as a parameter.
Something like:
services:
acme.twig.acme_extension:
class: Acme\DemoBundle\Twig\AcmeExtension
arguments: [#doctrine.dbal.default_connection]
tags:
- { name: twig.extension }
Details:
http://symfony.com/doc/current/cookbook/templating/twig_extension.html

Using getParameter() in admin class (not controller class)

namespace Acme\AdminBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use FOS\UserBundle\Model\UserManagerInterface;
class LessonAdmin extends Admin
{
public function
{
//I have tried these, but in vain.
$items = $this->container->getParameter('items');
or
$items = $this->getContainer()->getParameter('items');
I think this problem is related with Dependency Injection though, still unclear for me.
How can I inject getContainer item here??
In SonataAdmin, the DI container can be fetched from the Admin configuration pool:
<?php
use Sonata\AdminBundle\Admin\Admin;
class YourAdmin extends Admin
{
protected function yourAdminMethod()
{
$this->getConfigurationPool()->getContainer()->getParameter('your_parameter');
}
}
`
You can also inject parameters through setter in admin service definition:
services:
sonata.admin.lesson:
class: Acme\AdminBundle\Admin\LessonAdmin
tags:
- { name: sonata.admin, manager_type: orm, ...}
arguments:
- ~
- Acme\AppBundle\Entity\Lesson
- ~
calls:
- [ setItems, ["%items%"]]
And in your admin class:
class LessonAdmin extends Admin
{
public function setItems($items)
{
$this->items = $items;
}
In this way your parameter is accessible in your whole admin class.

Resources