Symfony2 Templating without request

前端 未结 4 2101
Happy的楠姐
Happy的楠姐 2021-02-15 12:14

I\'m trying to send an email from a ContainerAwareCommand in Symfony2. But I get this exception when the email template is render by:

$body = $this-         


        
相关标签:
4条回答
  • 2021-02-15 12:44

    Following BetaRide's answer put me on the right track but that wasn't sufficient. Then it was complaining: "Unable to generate a URL for the named route "" as such route does not exist."

    To create a valid request I've modified it to request the root of the project like so:

    $request = new Request();
    $request->create('/');
    $this->container->enterScope('request');
    $this->container->set('request', $request, 'request');
    

    You might need to call a different route (secured root?), root worked for me just fine.

    Symfony2 Docs

    Bonus addition:

    I had to do so much templating/routing in cli through Symfony2 commands that I've updated the initializeContainer() method in AppKernel. It creates a route to the root of the site, sets the router context and fakes a user login:

    protected function initializeContainer()
    {
        parent::initializeContainer();
        if (PHP_SAPI == 'cli') {
    
            $container = $this->getContainer();
    
            /**
             * Fake request to home page for cli router.
             * Need to set router base url to request uri because when request object
             * is created it perceives the "/portal" part as path info only, not base
             * url and thus router will not include it in the generated url's.
             */
            $request = Request::create($container->getParameter('domain'));
            $container->enterScope('request');
            $container->set('request', $request, 'request');
            $context = new RequestContext();
            $context->fromRequest($request);
            $container->get('router')->setContext($context);
            $container->get('router')->getContext()->setBaseUrl($request->getRequestUri());
    
            /**
             * Fake admin user login for cli. Try database read,
             * gracefully print error message if failed and continue.
             * Continue mainly for doctrine:fixture:load when db still empty.
             */
            try {
                $user = $container->get('fos_user.user_manager')->findUserByUsername('admin');
                if ($user !== null) {
                    $token = $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
                    $this->getContainer()->get('security.token_storage')->setToken($token);
                }
            } catch (\Exception $e) {
                echo "Fake Admin user login failed.\n";
            }
        }
    }
    

    You might not need the last $container->get('router')->getContext()->setBaseUrl($request->getRequestUri()); part, but I had to do it because my site root was at domain.com/siteroot/ and the router was stripping /siteroot/ away for url generation.

    0 讨论(0)
  • 2021-02-15 12:45

    You need to set the container into the right scope and give it a (fake) request. In most cases this will be enough:

    //before you render template add bellow code
    $this->getContainer()->enterScope('request');
    $this->getContainer()->set('request', new Request(), 'request');
    

    The full story is here. If you want to know the details read this issue on github.

    0 讨论(0)
  • 2021-02-15 12:54

    The problem arises because you use asset() function in your template.

    By default, asset() relies on Request service to generate urls to your assets (it needs to know what is the base path to you web site or what is the domain name if you use absolute asset urls, for example).

    But when you run your application from command line there is no Request.

    One way to fix this it to explicitely define base urls to your assets in config.yml like this:

    framework:
      templating:
        assets_base_urls: { http: ["http://yoursite.com"], ssl: ["http://yoursite.com"] }
    

    It is important to define both http and ssl, because if you omit one of them asset() will still depend on Request service.

    The (possible) downside is that all urls to assets will now be absolute.

    0 讨论(0)
  • 2021-02-15 13:01

    Since you don't have a request, you need to call the templating service directly like this:

    $this->container->get('templating')->render($template, $data);
    
    0 讨论(0)
提交回复
热议问题