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.
kaiser
You came here to know more about me? Here you go! I have been moderator on WordPress.StackExchange for several years. You can find me @unserkaiser on Twitter, where I also talk about building @gtmifylab, my current indie side project. Some of my older code bits can be found on GitHub franz-josef-kaiser. If you want to get in touch with me, then go with [email protected]. Please understand, that this isn't an additional support route and I won't answer such requests. Best wishes and keep building! Kaiser.
Updated on May 01, 2020Comments
-
kaiser about 4 years
Disclaimer: I'm slowly starting to get into Symfony and still have some problems understanding how the architecture works.
Currently I set up different Bundles (Services, right?) that should deliver different output for different routes. So far I got around adding a simple Twig template that loads stylesheets and scripts via Assetics and Twig-blocks. Now I added another Bundle that queries data via Buzz from a remote location, which worked fine as a standalone script, but I don't get around printing output in a Twig template.
The architecture of the original script is like the following (names made more generic):
- Vendors -
abstract
class that serves as base for all remote request Bundles. - ServiceABC -
abstract
class that extendsVendors
and defines Error handling and output preparation for the ABC service. - ClientXYZ -
final
class that extendsService_ABC
, defines output parsing and normalization of the returned data.
This Bundle got a
services.yml
file:# ~/MyApp/Bundle/ServiceABCBundle/Resources/config/services.yml parameters: service_abc_manager.class: MyApp\Bundle\ServiceABCBundle\Models\Service_ABC location_manager.class: MyApp\Bundle\ServiceABCBundle\Models\Clients\ClientLocation monitor_manager.class: MyApp\Bundle\ServiceABCBundle\Models\Clients\ClientMonitor services: service_abc_manager: abstract: true location_manager: class: %location_manager.class% parent: service_abc_manager monitor_manager: class: %monitor_manager.class% parent: service_abc_manager
Names changed for easier reference - Typos by accident possible.
Now my problem/question is, that I don't really get behind the Symfony2 concept of how to get the output into the template.
namespace MyApp\Bundle\ServiceABCBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use MyApp\Bundle\ServiceABCBundle\Models\Clients\ClientLocation; class DefaultController extends Controller { public function indexAction() { $services = array(); $services[] = $this->container->has('service_abc_manager'); $services[] = $this->container->has('location_manager'); $services[] = $this->container->has('client_location'); $services[] = $this->container->has('ClientLocation'); var_dump( $services ); $client = new ClientLocation(); var_dump( $client ); $response = $this->render( 'Service_ABC:Default:index.html.twig' ); # $response->setCharset( 'utf-8' ); # $response->headers->set( 'Content-Type', 'text/html' ); return $response; } }
The output of the first
array()
named$services
is alwaysfalse
and the$client = new ClientLocation();
throws an Exception that the class name wasn't found.How can I access those Services/Bundle(parts)/Classes? And how would I render the output to a template?
Update
After I added the complete tree definition to
Configuration()->getConfigTreeBuilder()
, I'm able to see the definitions in the CLI:class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root( 'myapp_service_abc' ); $rootNode ->children() ->scalarNode('service_abc_manager')->end() ->scalarNode('location_manager')->end() ->scalarNode('monitor_manager')->end() ->end() ; return $treeBuilder; } }
The CLI command
php app/console config:dump-reference myapp_service_abc
now gives me the following output:myapp_service_abc: service_abc_manager: ~ location_manager: ~ monitor_manager: ~
I can as well see that the config data was loaded, when I
var_dump( $loader );
insideMyAppServiceABCExtension
right after$loader->load( 'services.yml' );
was called.The output is the following:
object(Symfony\Component\DependencyInjection\Loader\YamlFileLoader) protected 'container' => object(Symfony\Component\DependencyInjection\ContainerBuilder) private 'definitions' => array 'service_abc_manager' => object(Symfony\Component\DependencyInjection\Definition) 'location_manager' => object(Symfony\Component\DependencyInjection\DefinitionDecorator) private 'parent' => string 'service_abc_manager' // etc.
The problem itself remains: There's still a
FALSE
return value insideDefaultController()->indexAction()
when Ivar_dump( $this->container->has( 'service_abc_manager' );
. I as well triedvar_dump( $this->container->has( 'location_manager' );
andvar_dump( $this->container->has( 'myapp.service_abc_manager' );
with the same result. - Vendors -
-
kaiser about 11 yearsThanks for your answer, but how could
$this->container->get('location_manager');
work ifhas()
already returnsfalse
? In fact I tried it like this and Symfony keeps telling me that the class doesn't exist while I can click through to it in my IDE... Maybe the problem is, that the Bundles are summed in one single namespace? Will have to inspect this one and come back reporting. And yes, I read the documentation very carefully, especially "the big picture". -
Alain Tiemblo about 11 yearsI guess the services.yml file is not loaded at all. Try to add a typo in it to be sure it is loaded, put your "Bundle" in a src/ filder... difficult to see what's wrong, it really looks like you did not used the command-line tools to generate your bundles.
-
kaiser about 11 yearsThe bundles were added via the CLI with
generate:bundle
. When I add typos, I get an Exception thrown. When I addapp/console config:dump-reference MyApp\ServiceABC
in the CLI, I getmyapp_service_abc []
in return. So I guess I got something wrong in either theDependencyInjection\Configuration.php
file with theTreeBuilder::root()
and the (not existing) tree definition (do I have to explicitly define it?) or something with some missing root node inservices.yml
. -
kaiser about 11 yearsI wrote an update to show you my progress. Still can't access the service in the
indexAction()
. -
kaiser about 11 yearsBtw: My
service.yml
file is inside the standard Symfony2 folder:~/MyApp/Bundle/ServiceABCBundle/Resources/config/services.yml
.