philiplb / CRUDlex

CRUDlex is an easy to use CRUD generator for Symfony 4 and Silex 2 which is great for auto generated admin pages
https://philiplb.de/crudlex/
MIT License
109 stars 23 forks source link

Identifier "twig.loader.filesystem" does not contain an object definition. #63

Closed germain-italic closed 7 years ago

germain-italic commented 8 years ago

Hi! Fresh install with Silex-Skeleton, composer edited to require Doctrine DBAL and CRUDlex (which implies more recent versions of twig-bridge and translation):

"require": {
        "php": ">=5.5.9",
        "silex/silex": "~2.0",
        "silex/web-profiler": "~2.0",
        "symfony/asset": "~2.8|3.0.*",
        "symfony/browser-kit": "~2.8|3.0.*",
        "symfony/class-loader": "~2.8|3.0.*",
        "symfony/config": "~2.8|3.0.*",
        "symfony/console": "~2.8|3.0.*",
        "symfony/css-selector": "~2.8|3.0.*",
        "symfony/debug": "~2.8|3.0.*",
        "symfony/finder": "~2.8|3.0.*",
        "symfony/form": "~2.8|3.0.*",
        "symfony/monolog-bridge": "~2.8|3.0.*",
        "symfony/process": "~2.8|3.0.*",
        "symfony/security": "~2.8|3.0.*",
        "symfony/translation": "3.1.*",
        "symfony/twig-bridge": "~3.1",
        "symfony/validator": "~2.8|3.0.*",
        "doctrine/dbal": "~2.2"
    },

Doctrine and Web Profiler working fine.

Adding CRUDlex:

        "philiplb/crudlex": "0.10.x-dev"

Instanciating the MySQLDataFactory, ServiceProvider: OK

Mounting the ControllerProvider results in this error:

InvalidArgumentException in Container.php line 233:
Identifier "twig.loader.filesystem" does not contain an object definition.

I've tried to tweak the Twig instanciation, with no result. However when I comment the Web Profiler instanciation:

$app->register(new WebProfilerServiceProvider(), array(
    'profiler.cache_dir' => __DIR__.'/../var/cache/profiler',
));

Then the error disappears and I can use CRUDlex.

So, it looks like issue #41 is back with the latest version.

Any idea?

philiplb commented 8 years ago

Hi, I had to add the LocaleServiceProvider to make it work again. I just adjusted the manual to it. This is what I ended up with:

<?php

/*
 * This file is part of the CRUDlex sample package.
 *
 * (c) Philip Lehmann-Böhm <philip@philiplb.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

$loader = require __DIR__.'/../vendor/autoload.php';
use Silex\Provider;
$app = new Silex\Application();

$app['debug'] = true;

$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
    'dbs.options' => array(
        'default' => array(
            'host'      => '127.0.0.1',
            'dbname'    => 'crud',
            'user'      => 'root',
            'password'  => '',
            'charset'   => 'utf8',
        )
    ),
));
$app->register(new Silex\Provider\SessionServiceProvider());

$app->register(new Silex\Provider\LocaleServiceProvider());
$app->register(new \Silex\Provider\TranslationServiceProvider(), array(
    'locale_fallbacks' => array('en'),
));

$dataFactory = new CRUDlex\MySQLDataFactory($app['db']);
$app->register(new CRUDlex\ServiceProvider(), array(
    'crud.file' => __DIR__ . '/../crud.yml',
    'crud.datafactory' => $dataFactory
));
$app->register(new Silex\Provider\TwigServiceProvider());

$app->register(new Provider\WebProfilerServiceProvider(), array(
    'profiler.cache_dir' => __DIR__.'/../cache/profiler',
    'profiler.mount_prefix' => '/_profiler', // this is the default
));

$app->register(new Provider\HttpFragmentServiceProvider());
$app->register(new Provider\ServiceControllerServiceProvider());

$app->mount('/crud', new CRUDlex\ControllerProvider());

$app->match('/', function() use ($app) {
    return $app->redirect($app['url_generator']->generate('crudList', array('entity' => 'library')));
})->bind('homepage');

$app->run();
germain-italic commented 8 years ago

Thanks for your help, after several tries I managed to make it work.

I had to move

$app->register(new Silex\Provider\WebProfilerServiceProvider(), array(
    'profiler.cache_dir' => __DIR__.'/../var/cache/profiler',
));

between CRUDlex registration and routes mounting. Then I had to add a namespace to my own templates:

$app['twig.loader.filesystem']->addPath(__DIR__.'/../templates', 'app');

I don't understand why those errors happen with 0.10, because I've been using the same project boilerplate for months (with 0.9). Probably related to other Silex dependencies I guess.

philiplb commented 8 years ago

I guess there where some changes from Silex 1.x to Silex 2 causing this, not 100% sure.

Wirone commented 7 years ago

@philiplb you need to extend twig.loader.filesystem like this:

// Silex 1.3
$app['twig.loader.filesystem'] = $app->share($app->extend('twig.loader.filesystem', function($twigLoader, $app) {
    $twigLoader->addPath(__DIR__.'/../templates', 'app');

    return $twigLoader;
}));

// Silex 2.0
$app->extend('twig.loader.filesystem', function($twigLoader, $app) {
    $twigLoader->addPath(__DIR__.'/../templates', 'app');

    return $twigLoader;
});

because $app['twig.loader.filesystem']->addPath() initializes the service and somehow it's not available anymore in Pimple container (for extending, which WebProfilerServiceProvider is trying to do).

philiplb commented 7 years ago

Fixed in https://github.com/philiplb/CRUDlex/commit/10a356a29a9337a97ddb45330cac782a398b2887

mamoot64 commented 7 years ago

Hi,

I would like to reopen this issue because the probleme seems not to be solved.

I work with Silex/Skeleton from Fabien Potencier and when I add Crudlex, there is an error on Twig.

Identifier "twig" does not contain an object definition.

Here, is my app.php :

<?php
use Silex\Application;
use Silex\Provider\AssetServiceProvider;
use Silex\Provider\TwigServiceProvider;
use Silex\Provider\ServiceControllerServiceProvider;
use Silex\Provider\HttpFragmentServiceProvider;

$app = new Application();
$app->register(new ServiceControllerServiceProvider());
$app->register(new AssetServiceProvider());
$app->register(new TwigServiceProvider());
$app->register(new HttpFragmentServiceProvider());

// Doctrine
$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
    'dbs.options' => array(
        'default' => array( )
    )
));

// Locale
$app->register(new Silex\Provider\LocaleServiceProvider());
$app->register(new \Silex\Provider\TranslationServiceProvider(), array(
    'locale_fallbacks' => array('en'),
));

// Crudlex
$dataFactory = new CRUDlex\MySQLDataFactory($app['db']);
$app->register(new CRUDlex\ServiceProvider(), array(
    'crud.file' => __DIR__ . '/../config/crud.yml',
    'crud.datafactory' => $dataFactory
));

// Twig own extension
$app['twig'] = $app->extend('twig', function ($twig, $app) {
    // here, it's work fine
    return $twig;
});

return $app;

If I comment code in the method "registerTwigExtensions" Crudlex\TwigExtensions, it's works (we have Twig errors but everything seems OK)

The container has the Twig object, but we don't pass the validation on extends method in Pimple :

<?php
if (!is_object($this->values[$id]) || !method_exists($this->values[$id], '__invoke')) {
    throw new \InvalidArgumentException(sprintf('Identifier "%s" does not contain an object definition.', $id));
}

is_object ==> ok method_exists ==> ko, because __invoke is not present in object which is a instance of Twig_Environment

If I comment Webprofiler Service Provider, it's work great.

Any ideas ?

Wirone commented 7 years ago

@acidline @philiplb it's because twig.loader.filesystem is not extended with closure, but called directly in ServiceProvider. Again.

mamoot64 commented 7 years ago

@Wirone Thank's for your answer, I did not look at this side because it's normaly fixed by the commit 10a356a

Now I have a probleme with the Translator Service Provider...

Identifier "translator" does not contain an object definition

If I deactivate Crudlex, everything work's fine !

Here is my composer.json :

"require": {
        "php": ">=5.5.9",
        "silex/silex": "~2.0",
        "silex/web-profiler": "~2.0",
        "symfony/asset": "3.*",
        "symfony/browser-kit": "3.*",
        "symfony/class-loader": "3.*",
        "symfony/config": "3.*",
        "symfony/console": "3.*",
        "symfony/css-selector": "3.*",
        "symfony/debug": "3.*",
        "symfony/finder": "3.*",
        "symfony/form": "3.*",
        "symfony/monolog-bridge": "3.*",
        "symfony/process": "3.*",
        "symfony/security": "3.*",
        "symfony/translation": "^3.2",
        "symfony/twig-bridge": "3.*",
        "symfony/validator": "3.*",
    "philiplb/crudlex": "0.11.x-dev as 0.10.0",
        "doctrine/migrations": "v1.2.2",
        "kurl/silex-doctrine-migrations-provider": "^0.2.1",
        "philiplb/crudlexuser": "0.12.x-dev"
    }
Wirone commented 7 years ago

@acidline it's because translator service is not properly extended too.

philiplb commented 7 years ago

Both is fixed and pushed, thank you for reporting.

mamoot64 commented 7 years ago

Sorry @philiplb, @Wirone, but the problem persists...

According to the Silex doc a better refactoring would be :

    protected function initLocales(Container $app) {

        $locales = $this->getLocales();

        $app->extend('translator', function(Translator $translator) use($locales) {
            $translator->addLoader('yaml', new YamlFileLoader());
            foreach ($locales as $locale) {
                $translator->addResource('yaml', __DIR__.'/../locales/'.$locale.'.yml', $locale);
            }
            return $translator;
        });

        return $locales;
    }

But I always have the problem...

Identifier "translator" does not contain an object definition.

Here is the stack trace :

  1. in Container.php line 233
  2. at Container->extend('translator', object(Closure)) in WebProfilerServiceProvider.php line 235
  3. at WebProfilerServiceProvider->register(object(Application)) in Container.php line 274
  4. at Container->register(object(WebProfilerServiceProvider), array('profiler.cache_dir' => '/home/nicolas/Documents/DEVELOPPEMENT/drivehome/drive/config/../var/cache/profiler')) in Application.php line 90
  5. at Application->register(object(WebProfilerServiceProvider), array('profiler.cache_dir' => '/home/nicolas/Documents/DEVELOPPEMENT/drivehome/drive/config/../var/cache/profiler')) in dev.php line 17
  6. at require('/home/nicolas/Documents/DEVELOPPEMENT/drivehome/drive/config/dev.php') in index_dev.php line 19
philiplb commented 7 years ago

Hi, your refactoring makes totally sense, thank you. I pushed it. Does this solve the problem for you? If not, can you post a minimal dev.php reproducing this behaviour?

mamoot64 commented 7 years ago

@philiplb Here is my files structure :

I use this Silex-Skeleton project with Crudlex.

index_dev.php

<?php
use Symfony\Component\Debug\Debug;

// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1'))
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}

require_once __DIR__.'/../vendor/autoload.php';

Debug::enable();

$app = require __DIR__.'/../src/app.php';
require __DIR__.'/../config/dev.php';
require __DIR__.'/../src/controllers.php';
$app->run();

src/app.php

<?php

use Silex\Application;
use Silex\Provider\AssetServiceProvider;
use Silex\Provider\TwigServiceProvider;
use Silex\Provider\ServiceControllerServiceProvider;
use Silex\Provider\HttpFragmentServiceProvider;
use Silex\Provider\WebProfilerServiceProvider;

$app = new Application();
$app->register(new ServiceControllerServiceProvider());
$app->register(new AssetServiceProvider());
$app->register(new TwigServiceProvider());
$app->register(new HttpFragmentServiceProvider());

// Doctrine
$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
    'dbs.options' => array(
        'default' => array(
            'host' => '',
            'dbname' => '',
            'user' => '',
            'password' => '',
            'charset' => 'utf8',
        )
    )
));

// Locale
$app->register(new Silex\Provider\LocaleServiceProvider());
$app->register(new \Silex\Provider\TranslationServiceProvider(), array(
    'locale_fallbacks' => array('en'),
));

// Crudlex
$dataFactory = new CRUDlex\MySQLDataFactory($app['db'], true); // true = UUID, id varchar 36
$app->register(new CRUDlex\ServiceProvider(), array(
    'crud.file' => __DIR__ . '/../config/crud.yml',
    'crud.datafactory' => $dataFactory
));

// Twig own extension
$app['twig'] = $app->extend('twig', function ($twig, $app) {
    return $twig;
});

// Crudlex user
$crudUserSetup = new CRUDlex\UserSetup();
$crudUserSetup->addEvents($app['crud']->getData('user'));
$userProvider = new CRUDlex\UserProvider($app['crud']->getData('user'), $app['crud']->getData('userRoles'));

$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls' => array(
        'login' => array(
            'pattern' => '^/login$',
        ),
        'admin' => array(
            'pattern' => '/admin',
            'http' => true,
            'users' => $userProvider,
            'form' => array(
                'login_path' => '/login',
                'check_path' => '/login_check'
            ),
            'logout' => array(
                'logout_path' => '/logout',
                'invalidate_session' => true
            ),
        ),
    ),
));

$app['security.access_rules'] = array(
    array('^/login$', 'ROLE_USER'),
    array('^/admin', ['ROLE_ADMIN'], 'https'),
    array('^/', ['ROLE_USER']),
);

return $app;

config/prod.php

<?php

// Twig
$app['twig.path'] = array(__DIR__.'/../templates');
$app['twig.options'] = array('cache' => __DIR__.'/../var/cache/twig');

config/dev.php

<?php

use Silex\Provider\MonologServiceProvider;
use Silex\Provider\WebProfilerServiceProvider;

// include the prod configuration
require __DIR__.'/prod.php';

// enable the debug mode
$app['debug'] = true;

$app->register(new MonologServiceProvider(), array(
    'monolog.logfile' => __DIR__.'/../var/logs/silex_dev.log',
));

$app->register(new WebProfilerServiceProvider(), array(
    'profiler.cache_dir' => __DIR__.'/../var/cache/profiler',
));
philiplb commented 7 years ago

I moved the initialization of twig and the translator to the boot phase of the service provider. Does that fix the problem for you? My local tests are positive, for me it works both ways, either having the other providers registered in my index.php or not.

philiplb commented 7 years ago

I assume all is good. Just reopen if not. :)

mikred00 commented 6 years ago

Hi, i'm testing Cruldlex User but like acidline i have some problem with translator: When i put in index.php $crudUserSetup->addEvents($app['crud']->getData('user'));

Fatal error: Uncaught exception 'Pimple\Exception\UnknownIdentifierException' with message ' Identifier "translator" is not defined. ' in /Silex/vendor/pimple/pimple/src/Pimple/Container.php:101 Stack trace:

0 /Silex/vendor/philiplb/crudlex/src/CRUDlex/ServiceProvider.php(79): Pimple\Container->offsetGet('translator')

1 /Silex/vendor/philiplb/crudlex/src/CRUDlex/ServiceProvider.php(227): CRUDlex\ServiceProvider->initLocales(Object(Silex\Application))

2 /Silex/vendor/philiplb/crudlex/src/CRUDlex/ServiceProvider.php(253): CRUDlex\ServiceProvider->init(NULL, Object(Silex\Application))

3 /Silex/vendor/pimple/pimple/src/Pimple/Container.php(118): CRUDlex\ServiceProvider->CRUDlex{closure}(Object(Silex\Application))

4 /Silex/web/index.php(43): Pimple\Container->offsetGet('crud')

5 {main} thrown in /Silex/vendor/pimple/pimple/src/Pimple/Container.php on line 101

i'm very newbie thank you