Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deploying a Symfony app - ClassNotFoundException Error

I am learning the Symfony framework and trying to deploy a simple boilerplate app I put together to Heroku using Git.

The deployment fails due to the following fatal error:

Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "WebServerBundle" from namespace "Symfony\Bundle\WebServerBundle

Did you forget a "use" statement for another namespace? in /tmp/build_cbeb92af6c9ee04b07e1f85618211649/src/Kernel.php:32

Kernel.php

<?php

namespace App;

use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;

class Kernel extends BaseKernel {

    use MicroKernelTrait;

    const CONFIG_EXTS = '.{php,xml,yaml,yml}';

    public function getCacheDir(){

        return $this->getProjectDir().'/var/cache/'.$this->environment;
    }

    public function getLogDir(){

        return $this->getProjectDir().'/var/log';
    }

    public function registerBundles(){

        $contents = require $this->getProjectDir().'/config/bundles.php';
        foreach ($contents as $class => $envs) {
            if (isset($envs['all']) || isset($envs[$this->environment])) {
                yield new $class();
            }
        }
    }

    protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader){

        $container->setParameter('container.autowiring.strict_mode', true);
        $container->setParameter('container.dumper.inline_class_loader', true);
        $confDir = $this->getProjectDir().'/config';
        $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob');
        if (is_dir($confDir.'/packages/'.$this->environment)) {
            $loader->load($confDir.'/packages/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');
        }
        $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob');
        $loader->load($confDir.'/services_'.$this->environment.self::CONFIG_EXTS, 'glob');
    }

    protected function configureRoutes(RouteCollectionBuilder $routes){

        $confDir = $this->getProjectDir().'/config';
        if (is_dir($confDir.'/routes/')) {
            $routes->import($confDir.'/routes/*'.self::CONFIG_EXTS, '/', 'glob');
        }
        if (is_dir($confDir.'/routes/'.$this->environment)) {
            $routes->import($confDir.'/routes/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob');
        }
        $routes->import($confDir.'/routes'.self::CONFIG_EXTS, '/', 'glob');
    }
}

What Ive done so far:

  • install the dotenv bundle (composer require symfony/dotenv)
  • run composer dump-autoload
  • set the production environment variable via the heroku CLI as per this article (heroku config:set SYMFONY_ENV=prod)

Some things Ive learned/have noticed:

  • According to the README file for WebServerBundle:

WebServerBundle provides commands for running applications using the PHP built-in web server. It simplifies your local development setup because you don't have to configure a proper web server such as Apache or Nginx to run your application.

.. that is, WebServerBundle is a development dependency - yet it is being included in production.

  • WebServerBundle is also being included in the composer.lock file under autoload

    "autoload": { "psr-4": { "Symfony\\Bundle\\WebServerBundle\\": "" }, ... },

  • My bundles.php file includes WebServerBundle for dev

    return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], ];

  • I have a .env file and a .env.dist file - Im assuming the .env.dist file is for production? They both have the same contents:

    APP_ENV=dev APP_SECRET=0473d15a4ce2723619d2e8b0405186d3

Im pretty new to symfony and do not really understand how a production environment is instantiated other than that the dotenv bundle reads the .env file and sets the environment variables.

Any help and clarity on all of this would be appreciated.

Edit: here is my composer.json file

{
    "type": "project",
    "license": "proprietary",
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "sensio/framework-extra-bundle": "^5.1",
        "symfony/asset": "^4.0",
        "symfony/console": "^4.0",
        "symfony/dotenv": "^4.0",
        "symfony/flex": "^1.0",
        "symfony/framework-bundle": "^4.0",
        "symfony/lts": "^4@dev",
        "symfony/twig-bundle": "^4.0",
        "symfony/yaml": "^4.0"
    },
    "require-dev": {
        "symfony/profiler-pack": "^1.0",
        "symfony/web-server-bundle": "^4.0"
    },
    "config": {
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "replace": {
        "symfony/polyfill-apcu": "*",
        "symfony/polyfill-php70": "*",
        "symfony/polyfill-php56": "*"
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd",
            "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    },
    "conflict": {
        "symfony/symfony": "*"
    },
    "extra": {
        "symfony": {
            "id": "01C1BVQJ19BG3WAS3299PDHH9P",
            "allow-contrib": false
        }
    }
}
like image 623
yevg Avatar asked Feb 24 '18 20:02

yevg


1 Answers

I'm not sure about the command you are using, (I use git)

heroku config:set SYMFONY_ENV=prod

But if your .env file has

APP_ENV=dev

That is explictly setting the environment to dev, so it is trying to load dev dependencies (proven by your error) which don't get pushed to the server(read the article you provided).

You need the .env file that is on the server to have APP_ENV=prod The .env is for the specific machine, it is ignored by git, while .env.dist is tracked. So edit the .env.dist and commit it, then once it is on the server just rename it .env then I would run composer install or composer update on the server which will update dependencies and clear the cache. Then refresh your browser.

like image 185
Arleigh Hix Avatar answered Oct 03 '22 05:10

Arleigh Hix