简体   繁体   中英

symfony2: class loading/namespace handling - difference between prod/dev environments?

what's exactly the difference in class autoloading and namespace handling between symfony2's app_dev.php and app.php or dev/prod environment (symfony 2.8.4).

When I run it in dev environment through app_dev.php all is fine, when I run it in prod through app.php I get an Internal Server error 500 (nothing written in symfony's prod.log). Looking into apache's error.log I see:

PHP Fatal error:  Class 'SSMCRM\\Common\\ProductionTemplateMapper' not found in /var/[...]

And yes, I cleared the prod cache...

app.php:

use Symfony\Component\HttpFoundation\Request;

/**
 * @var Composer\Autoload\ClassLoader
 */
$loader = require __DIR__.'/../app/autoload.php';
include_once __DIR__.'/../app/bootstrap.php.cache';

// Enable APC for autoloading to improve performance.
// You should change the ApcClassLoader first argument to a unique prefix
// in order to prevent cache key conflicts with other applications
// also using APC.
/*
$apcLoader = new Symfony\Component\ClassLoader\ApcClassLoader(sha1(__FILE__), $loader);
$loader->unregister();
$apcLoader->register(true);
*/

//require_once __DIR__.'/../app/AppCache.php';

$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
//$kernel = new AppCache($kernel);

// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
//Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

app_dev.php:

<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;

// If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#checking-symfony-application-configuration-and-setup
// for more information
//umask(0000);

// 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',
                                                  '192.168.33.1', //for vagrant box
        )) || php_sapi_name() === 'cli-server')
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}

/**
 * @var Composer\Autoload\ClassLoader $loader
 */
$loader = require __DIR__.'/../app/autoload.php';
Debug::enable();

$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

in the autoload.php I added our legacy classes to the loader:

$loader->add('SSMCRM', __DIR__.'/../web/legacy/classes');

I found the failure. For each legacy PHP file which was called directly now we have a route which leads to our wrapper (to make the symfony features available in the legacy code). I generated the controller and it's routenames and paths from the real URLs so in the first step we didn't need to rewrite all links and javascript AJAX calls and to make find/replace actions easier later. The result is sth. like that:

/**
 * @Route(
 * path="ajax/ajax_admin_vorlagen_web2print_detail.php",
 * name="pages/admin/ajax/ajax_admin_vorlagen_web2print_detail.php",
 * options={"expose"=true}
 * )
 */
public function ajax_admin_vorlagen_web2print_detailAction()
{
    return $this->returnLegacyResponse('pages/admin/ajax/ajax_admin_vorlagen_web2print_detail.php');
}

This works absolutely fine in dev environment, symfony's routing is executed and we get to the corresponding action. But it seems that in prod environment symfony looks first for the file itself (maybe for better speed?) and skips the route matching if the file exists. If our file is called directly there is no symfony autoloader and we removed recently our legacy autoloader. That's why the class is missing...

So the simple solution is to rename all affected paths (eg remove the ".php").

I couldn't find anything about this differences between prod/dev environment in kernel processing in the docs. :(

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM