1
votes

I'm trying to set a twig filter working this way: {{entities|fieldnames}} that will return an array containing the properties names of a entity object. My problem, after reading and trying for hours, is that I'm not able to execute $this->container->get("helpers") from the Twig Extension php. It seems that I'm not linking the service container properly... Help, please ;)

Error: Call to a member function get() on a non-object in /Users/a77/Dropbox/06.Proyectos/2011 U-Vox/DEV U-Vox/Uvox Web/src/Acme/DemoBundle/Extension/FieldnamesTwigExtension.php line 38

Or if construct without =null Error ContextErrorException: Catchable Fatal Error: Argument 1 passed to Acme\DemoBundle\Extension\FieldnamesTwigExtension::__construct() must be an instance of Acme\DemoBundle\Extension\Container, none given, called in

services.yml

services:

helpers:
    class:        Acme\DemoBundle\Services\Helpers

twig.extension.acme.demo:
    class:        Acme\DemoBundle\Twig\Extension\DemoExtension
    arguments:    [twig.loader]

acme.demo.listener:
    class:        Acme\DemoBundle\EventListener\ControllerListener
    arguments:    [twig.extension.acme.demo]

fieldnames:
    class: Acme\DemoBundle\Extension\FieldnamesTwigExtension
    arguments:  [@service_container]

Extension\FieldnamesTwigExtension.php

use Symfony\Component\DependencyInjection\ContainerInterface as Container;
namespace Acme\DemoBundle\Extension;

class FieldnamesTwigExtension extends \Twig_Extension {
private $container;
public function __construct(Container $container=null)
{
    $this->container = $container;
    //var_dump ($container); exit; //  prints null !!!

}
 protected function get($service)
{
    return $this->container->get($service);
}

public function getFilters() {
    return array(
        'fieldnames' => new \Twig_Filter_Method($this, 'fieldnamesFilter'),
    );
}

public function getName() {
    return 'fieldnames_twig_extension';
}

public function fieldnamesFilter($obj) {
    if (is_array($obj)) {
        $first = $obj[0];

// GET (HELPERS) NOT WORKING :

       $fieldnames = $this->container->get("helpers")->getFieldnames($first);
        return $fieldnames;
    }
    return null;
}

public function twig_array_get_function($array, $name) {
    return $array[$name];
}

}

Helpers.php

namespace Acme\DemoBundle\Services;

class Helpers {

public function sum($n1, $n2) {
    return $n1 + $n2;
}

public function getFieldnames($entities) {
    $reflect = new \ReflectionClass($entities[0]);
    $props = $reflect->getProperties();
    $fieldnames = Array();
    foreach ($props as $prop) {
        $fieldnames[] = $prop->getName();
    }
    return $fieldnames;
 }

}

AcmeDemoExtension.php

namespace Acme\DemoBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Definition; // Added

class AcmeDemoExtension extends Extension {

public function load(array $configs, ContainerBuilder $container) {

    $definition = new Definition('Acme\DemoBundle\Extension\AccessTwigExtension');
    $definition->addTag('twig.extension');
    $container->setDefinition('access_twig_extension', $definition);

    $definition2 = new Definition('Acme\DemoBundle\Extension\FieldnamesTwigExtension');
    $definition2->addTag('twig.extension');
    $container->setDefinition('fieldnames_twig_extension', $definition2);


    $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
    $loader->load('services.yml');
}

public function getAlias() {
    return 'acme_demo';
}

 }
3
If you want to make this works, you should put "namespace" before "use", remove the "definition" lines and finally update the getFieldnames to public function getFieldnames($record) { $reflect = new \ReflectionClass($record); $props = $reflect->getProperties(); $fieldnames = Array(); foreach ($props as $prop) { $fieldnames[] = $prop->getName(); } return $fieldnames; }Arco Voltaico

3 Answers

5
votes

I tried your code on my application and had the same error. To resolve it :

Acme\DemoBundle\DependencyInjection\AcmeDemoExtension.php

Remove this lines :

$definition2 = new Definition('Acme\DemoBundle\Extension\FieldnamesTwigExtension');
$definition2->addTag('twig.extension');
$container->setDefinition('fieldnames_twig_extension', $definition2);

Acme\DemoBundle\Resources\config\services.yml

Replace this lines:

fieldnames:
    class: Acme\DemoBundle\Extension\FieldnamesTwigExtension
    arguments:  [@service_container]

By :

fieldnames:
    class: Acme\DemoBundle\Extension\FieldnamesTwigExtension
    arguments:  [@service_container]
    tags: [{ name: twig.extension }]
2
votes

You are making this too hard. You should be injecting helpers directly into you twig extension. You should also be doing your tagging in services.yml. Not in the dependency injection extension.

http://symfony.com/doc/current/cookbook/templating/twig_extension.html

services.yml

fieldnames:
    class: Acme\DemoBundle\Extension\FieldnamesTwigExtension
    arguments:  [@helpers]
    tags:
        - { name: twig.extension }

And adjust the rest of your code accordingly.

1
votes

In your Extension\FieldnamesTwigExtension.php, is this normal that your namespace is called after use instruction ?

Which error Symfony return ?