Symfony2: How to Access Service from Template

symfony2: how to access service from template

You can set the service a twig global variable in config.yml, e.g

#app/config/config.yml
twig:
globals:
your_service: "@your_service"

And in your template.html.twig file you can invoke your service this way:

{{ your_service.someMethod(twig_variable) }}

See here.

Accessing Method Through Service --- Symfony2

When you call $this->get("your.service") you are asking the dependency injection container to load that service. You are requesting that it loads one of your controllers which extends Symfony's controller class which extends ContainerAware. The error you are getting is because the loaded controller is likely trying to access a service like "request" using $this->container->get("request") but $this->container is not set.

ContainerAware has a method setContainer which you can actually run when your service is setup by using the calls: argument in services.yml:

services:
cj.businessbundle.purchase:
class: CJ\BusinessBundle\Controller\PurchaseController
calls:
- [setContainer, [@service_container]]

Symfony2 does this for the loaded controller (PurchaseOrderController) but not if you just load a controller class yourself.

It would be much better practice to extract the newAction (or the required logic) from PurchaseController as a service itself rather than setting the whole controller as a service. This way both Purchase and PurchaseOrder controllers can call the service to create a new purchase (or whatever newAction does) and you are not loading a whole controller everytime. Check out the FOS user bundle user manager for a good example of a service or http://symfony.com/doc/2.1/book/service_container.html#what-is-a-service

Access Service from Controller and/or Twig template

You should not call your services from the twig file, but from the controller.

The role of the controller is to :

  • validate your forms if there were a form posted
  • call your services to get some stuffs to display in a view
  • initialize forms if there is a form to display
  • return a Response that typically contains a rendered twig view

Do not call your services using something like $client = new ClientLocation();, but call it using the service container. This will allow you to take the whole power of the dependancy injection offered by Symfony2.

Your controller will look like :

<?php

namespace MyApp\Bundle\ServiceABCBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{

public function indexAction()
{
$locationService = $this->container->get('location_manager');

$someStuffs = $locationService->someMethod();

$response = $this->render(
'ServiceABCBundle:Default:index.html.twig', array('stuffs' => $someStuffs)
);

return $response;
}

}

From your twig file, you'll be able to use the stuffs variable :

  • {{ stuffs }} if your variable is a terminal ( a string, a number... )
  • {{ stuffs.attribute }} if your variable is an object or an array

About your services file, I am a bit confused, because your architecture does not look to be the standard Symfony2's one :

# ~/MyApp/Bundle/ServiceABCBundle/Resources/config/services.yml

Why your services.yml file isn't in the src/MyApp/SomethingBundle/Resources/config/ directory?

If you didn't already read it, I suggest you to have a look to the Symfony2 : The Big Picture documentation, which is the best way to start with Symfony2.

Call a service from twig template in symfony 4

You can still define twig global variables - they would just go in with the rest of the Twig configuration in config/packages/twig.yaml.

An alternative, and maybe better place to put that could be a Twig function. The service that defines the function (or filters) are as much a service as the controllers, and so you would type-hint your NavigationGenerator and anything else you needed, in the constructor, for use in the function that is being called from Twig.

How to call a service in my twig template to create a form with Symfony 2

You should start by making sure that you really have to use a form to do the manipulations that you are trying to do. Maybe using a link to a page with the form would suffice.

But this doesn't not answer your question so here goes:
Since the form will be used on every page it should be placed in your main template, in this case the base.html.twig. In fact, the content in the <main> and <header> tags should be moved to your base template. Then, you should add an action in your controller which handles the form or just rename the indexAction giving it a name more related to what you are trying to accomplish. After, you will move the code from the form in another template without any of you block tags.

menu.html.twig

{{ form_start(formulaire) }}
{{ form_widget(formulaire.Ajouter) }}
{{ form_widget(formulaire.projet) }}
{{ form_row(formulaire.modifier) }}
{{ form_row(formulaire.supprimer) }}
{{ form_end(formulaire) }}

controller

use Symfony\Component\HttpFoundation\Request;

class AdminController extends Controller
...

public function menuAction() {
$request = Request::createFromGlobals();

// code that was in the indexAction

return $this->render('AdminBundle::menu.html.twig', array(
'formulaire'=>$formulaire->createView()
));
}
}

In your base you will render the action.

base.html.twig

{{ render(controller('AdminBundle:Admin:menu')) }}

You can also find more documentation on this page:
http://symfony.com/doc/current/book/templating.html

Symfony2 - How to implement this search function as a service?

If you are trying to inject the request service, you would be better to inject the request_stack service instead and access the current Request by calling the getCurrentRequest()

class Search
{
protected $request;

public function __construct(RequestStack $requestStack)
{
$this->request = $requestStack->getCurrentRequest();
//Do any kinds of initializing you need
}

public function mySearch()
{
$results = null;
$query = $this->request->query->get('q');
//Do your search base on $query
//I suggest to send the container instead of RequestStack because you want to do search by using EntityManger, too
//Return the results
}
}

and change your service.yml as below and set the scope to "request"

services:
search:
class: Acme\ProjectBundle\Services\Search
arguments: ["@request_stack"]
scope: "request"

You also have another option to send the container as a parameter to your service and in your service use container->getRequset()

Symfony - Service in Twig template

You can access the logged in user data directly in the twig template without requesting anything in the controller. The user is accessible like this : app.user.

I would add a method hasGroup to your User object then you can call that method in your twig template to test if a user belongs to a group.

If you did this then you can just do this:

{% if app.user.hasGroup('groupName') %} 
//do something
{% endif %}

Symfony2.8 how to build a search form that will be viewable from all templates

This could be achieved injecting a service into all templates as global variable:

First, define your service with its dependencies:

services:
app.fulltextsearch:
class: MyBundle\Services\FulltextSearch
arguments: ['@form.factory']

Second, to define this service as a global Twig variable:

# app/config/config.yml
twig:
# ...
globals:
fulltextSearch: '@app.fulltextsearch'

That's it!

Whenever the global variable is accessed in the template, the service will be requested from the service container and you get access to that object.


On the other hand, I suggest you create the whole form within FulltextSearch::mySearch method for major reusability:

class FulltextSearch
{
private $router;

//...

public function mySearch() {
$form = $this->formFactory->createBuilder()
->setAction($this->router->generate('my_search'))
->add('search', FulltextSearch::class)
->getForm();

return $form->createView();
}
}

Note: Make sure to inject the @router service in app.fulltextsearch definition as well as '@form.factory'.

Next, you base search template looks like this, (no needed <form> tag, action and method attributes, this last by default is POST):

{{ form(fulltextSearch.mySearch) }}


Related Topics



Leave a reply



Submit