mtymek/blast-base-url

Cannot use urlhelper on subdirectory with blast/urlHelper

Closed this issue · 6 comments

Hello,
I have followed the cookbook guide relative to use zend expressive on subdirectory. And the default homepage action works fine. I'm using the expressive skeleton.

Unfortunately I'm unable to make this work as i receive the following error:
Catchable fatal error: Argument 1 passed to Zend\Expressive\Helper\UrlHelperMiddleware::__construct() must be an instance of Zend\Expressive\Helper\UrlHelper, none given, called in /home/ubuntu/workspace/vendor/zendframework/zend-expressive/src/MarshalMiddlewareTrait.php on line 124 and defined in /home/ubuntu/workspace/vendor/zendframework/zend-expressive-helpers/src/UrlHelperMiddleware.php on line 27

This is my dependencies config file:

<?php
use Zend\Expressive\Application;
use Zend\Expressive\Container\ApplicationFactory;
use Zend\Expressive\Helper;

return [
    // Provides application-wide services.
    // We recommend using fully-qualified class names whenever possible as
    // service names.
    'dependencies' => [
        // Use 'invokables' for constructor-less services, or services that do
        // not require arguments to the constructor. Map a service name to the
        // class name.
        'invokables' => [
            // Fully\Qualified\InterfaceName::class => Fully\Qualified\ClassName::class,
            Helper\ServerUrlHelper::class => Helper\ServerUrlHelper::class,
            Blast\BaseUrl\BasePathHelper::class => Blast\BaseUrl\BasePathHelper::class,
        ],
        // Use 'factories' for services provided by callbacks/factory classes.
        'factories' => [
            Application::class => ApplicationFactory::class,
            Doctrine\DBAL\DriverManager::class     => App\Catalog\Factory\DoctrineDbalConnectionFactory::class,
            Blast\BaseUrl\UrlHelper::class       => Blast\BaseUrl\UrlHelperFactory::class,
            App\Catalog\Config\ConfigDbMiddleware::class => App\Catalog\Factory\ConfigDbMiddlewareFactory::class,
            bitExpert\Http\Middleware\Psr7\Prophiler\ProphilerMiddleware::class => App\Catalog\Factory\ProphilerFactory::class,
            App\Catalog\Http\UserAgentMiddleware::class => App\Catalog\Factory\UserAgentMiddlewareFactory::class,
            App\Catalog\Log\LogMiddleware::class         => App\Catalog\Factory\LogMiddlewareFactory::class,
            App\Catalog\Http\SessionMiddleware::class => App\Catalog\Factory\SessionMiddlewareFactory::class,
            App\Catalog\Http\SessionHandlerMiddleware::class => App\Catalog\Factory\SessionHandlerFactory::class,
            Aura\Session\Session::class         => App\Catalog\Factory\AuraSessionFactory::class,
            Doctrine\ORM\EntityManager::class  => App\Catalog\Factory\DoctrineFactory::class,
            Doctrine\Common\Cache\Cache::class => App\Catalog\Factory\DoctrineFileCacheFactory::class,
            App\Catalog\i18n\LanguageMiddleware::class => App\Catalog\Factory\LanguageMiddlewareFactory::class,
            App\Catalog\Mail\MailMiddleware::class => App\Catalog\Factory\MailMiddlewareFactory::class,
        ],
        'aliases' => [
            // alias default UrlHelper with Blast\BaseUrl alternative
            Helper\UrlHelper::class => Blast\BaseUrl\UrlHelper::class,
        ],
    ],
];

And this the middleware pipeline

<?php
use Zend\Expressive\Container\ApplicationFactory;
use Zend\Expressive\Helper;
use Zend\Expressive\App;

return [
    'dependencies' => [
        'invokables' => [
            /* ... */
        ],
        'factories' => [
            Helper\ServerUrlMiddleware::class => Helper\ServerUrlMiddlewareFactory::class,
        //    Helper\UrlHelperMiddleware::class => Helper\UrlHelperMiddlewareFactory::class,
            Helper\UrlHelper::class => Helper\UrlHelperFactory::class,
            Blast\BaseUrl\BaseUrlMiddleware::class => Blast\BaseUrl\BaseUrlMiddlewareFactory::class,
        ],
    ],
    // This can be used to seed pre- and/or post-routing middleware
    'middleware_pipeline' => [
        // An array of middleware to register. Each item is of the following
        // specification:
        //
        // [
        //  Required:
        //     'middleware' => 'Name or array of names of middleware services and/or callables',
        //  Optional:
        //     'path'     => '/path/to/match', // string; literal path prefix to match
        //                                     // middleware will not execute
        //                                     // if path does not match!
        //     'error'    => true, // boolean; true for error middleware
        //     'priority' => 1, // int; higher values == register early;
        //                      // lower/negative == register last;
        //                      // default is 1, if none is provided.
        // ],
        //
        // While the ApplicationFactory ignores the keys associated with
        // specifications, they can be used to allow merging related values
        // defined in multiple configuration files/locations. This file defines
        // some conventional keys for middleware to execute early, routing
        // middleware, and error middleware.
        'always' => [
            'middleware' => [
                // Add more middleware here that you want to execute on
                // every request:
                // - bootstrapping
                // - pre-conditions
                // - modifications to outgoing responses
                Helper\ServerUrlMiddleware::class,
                Blast\BaseUrl\BaseUrlMiddleware::class,
                bitExpert\Http\Middleware\Psr7\Prophiler\ProphilerMiddleware::class,
                \App\Catalog\Config\ConfigDbMiddleware::class,
                \App\Catalog\Http\SessionHandlerMiddleware::class,
                \App\Catalog\Http\UserAgentMiddleware::class,
                \App\Catalog\Http\SessionMiddleware::class,
            ],
            'priority' => 10000,
        ],

        'routing' => [
            'middleware' => [
                ApplicationFactory::ROUTING_MIDDLEWARE,
                // Add more middleware here that needs to introspect the routing
                // results; this might include:
                // - route-based authentication
                // - route-based validation
                // - etc.
                Helper\UrlHelperMiddleware::class,
                \App\Catalog\i18n\LanguageMiddleware::class, 
                ApplicationFactory::DISPATCH_MIDDLEWARE,
            ],
            'priority' => 1,
        ],

        'error' => [
            'middleware' => [
                \App\Catalog\Log\LogMiddleware::class,
            ],
            'error'    => true,
            'priority' => -10000,
        ],
    ],
];

Closed because it has been answered there: zendframework/zend-expressive#282 (comment)

Actually this is still open :) I will close after ensuring it works.

@acidvertigo I just realized that it happens because you have factory definition commented out (in middleware pipeline config):

'factories' => [
    // ...
    // here:
    //    Helper\UrlHelperMiddleware::class => Helper\UrlHelperMiddlewareFactory::class,
    // ..
],

Uncomment this line and it should start working.

Ok, i have tested with latest release and seems that works, thank you.

However the other funny things that happens is that if i have my zend expressive installation on this url: "http://www.mysite.com/vela"

if use this code to test:
This is my FastRoute route:

[
            'name' => 'admin',
            'path' => '/vela/admin/login',
            'middleware' => App\Action\AdminLoginPageAction::class,
            'allowed_methods' => ['GET'],
        ],

And this debug code to see the generated url

var_dump($this->helper->generate('admin'));

I get the correct url: /vela/admin/login

Instead if i use the route (taken from multilanguage cookbook):

        [
            'name' => 'home',
            'path' => '/vela/{locale:[a-z]{2}}',
            'middleware' => App\Action\HomePageAction::class,
            'allowed_methods' => ['GET'],
        ],

And this debug code to see the generated url

var_dump($this->helper->generate('home', ['locale' => 'it']));

I get the wrong url: /vela/it}

I get an extra "}" in the url it should be /vela/it

Seems that the regex in fastroute configuration is not handled correctly.

Here my modified and cleaned dependencies.php file:

<?php
use App\Catalog;
use bitExpert\Http\Middleware\Psr7\Prophiler;
use Zend\Expressive\Application;
use Zend\Expressive\Container\ApplicationFactory;
use Zend\Expressive\Helper;

return [
    // Provides application-wide services.
    // We recommend using fully-qualified class names whenever possible as
    // service names.
    'dependencies' => [
        // Use 'invokables' for constructor-less services, or services that do
        // not require arguments to the constructor. Map a service name to the
        // class name.
        'invokables' => [
            // Fully\Qualified\InterfaceName::class => Fully\Qualified\ClassName::class,
            Helper\ServerUrlHelper::class => Helper\ServerUrlHelper::class,

        ],
        // Use 'factories' for services provided by callbacks/factory classes.
        'factories' => [
            Application::class                           => ApplicationFactory::class,
            Aura\Session\Session::class                  => Catalog\Factory\AuraSessionFactory::class,
            Catalog\Config\ConfigDbMiddleware::class     => Catalog\Factory\ConfigDbMiddlewareFactory::class,
            Catalog\Http\UserAgentMiddleware::class      => Catalog\Factory\UserAgentMiddlewareFactory::class,
            Catalog\i18n\LanguageMiddleware::class       => Catalog\Factory\LanguageMiddlewareFactory::class,
            Catalog\Log\LogMiddleware::class             => Catalog\Factory\LogMiddlewareFactory::class,
            Catalog\Mail\MailMiddleware::class           => Catalog\Factory\MailMiddlewareFactory::class,
            Catalog\Http\SessionMiddleware::class        => Catalog\Factory\SessionMiddlewareFactory::class,
            Catalog\Http\SessionHandlerMiddleware::class => Catalog\Factory\SessionHandlerFactory::class,
            Doctrine\Common\Cache\Cache::class           => Catalog\Factory\DoctrineFileCacheFactory::class,
            Doctrine\DBAL\DriverManager::class           => Catalog\Factory\DoctrineDbalConnectionFactory::class,
            Doctrine\ORM\EntityManager::class            => Catalog\Factory\DoctrineFactory::class,
            Helper\UrlHelper::class                      => Helper\UrlHelperFactory::class,
            Prophiler\ProphilerMiddleware::class         => Catalog\Factory\ProphilerFactory::class,
        ],
    ],
];

and my middleware pipeline:

<?php
use App\Catalog;
use Blast\BaseUrl;
use bitExpert\Http\Middleware\Psr7\Prophiler;
use Zend\Expressive\Container\ApplicationFactory;
use Zend\Expressive\Helper;
use Zend\Expressive\App;

return [
    'dependencies' => [
        'invokables' => [
            /* ... */
        ],
        'factories' => [
            Helper\ServerUrlMiddleware::class => Helper\ServerUrlMiddlewareFactory::class,
            Helper\UrlHelperMiddleware::class => Helper\UrlHelperMiddlewareFactory::class,
          //  Helper\UrlHelper::class           => Helper\UrlHelperFactory::class,
            BaseUrl\BaseUrlMiddleware::class  => BaseUrl\BaseUrlMiddlewareFactory::class,
        ],
    ],
    // This can be used to seed pre- and/or post-routing middleware
    'middleware_pipeline' => [
        // An array of middleware to register. Each item is of the following
        // specification:
        //
        // [
        //  Required:
        //     'middleware' => 'Name or array of names of middleware services and/or callables',
        //  Optional:
        //     'path'     => '/path/to/match', // string; literal path prefix to match
        //                                     // middleware will not execute
        //                                     // if path does not match!
        //     'error'    => true, // boolean; true for error middleware
        //     'priority' => 1, // int; higher values == register early;
        //                      // lower/negative == register last;
        //                      // default is 1, if none is provided.
        // ],
        //
        // While the ApplicationFactory ignores the keys associated with
        // specifications, they can be used to allow merging related values
        // defined in multiple configuration files/locations. This file defines
        // some conventional keys for middleware to execute early, routing
        // middleware, and error middleware.
        'always' => [
            'middleware' => [
                // Add more middleware here that you want to execute on
                // every request:
                // - bootstrapping
                // - pre-conditions
                // - modifications to outgoing responses
                Helper\ServerUrlMiddleware::class,
                BaseUrl\BaseUrlMiddleware::class,
                Prophiler\ProphilerMiddleware::class,
                Catalog\Config\ConfigDbMiddleware::class,
                Catalog\Http\SessionHandlerMiddleware::class,
                Catalog\Http\UserAgentMiddleware::class,
                Catalog\Http\SessionMiddleware::class,
            ],
            'priority' => 10000,
        ],

        'routing' => [
            'middleware' => [
                ApplicationFactory::ROUTING_MIDDLEWARE,
                // Add more middleware here that needs to introspect the routing
                // results; this might include:
                // - route-based authentication
                // - route-based validation
                // - etc
                Helper\UrlHelperMiddleware::class,
                Catalog\i18n\LanguageMiddleware::class, 
                ApplicationFactory::DISPATCH_MIDDLEWARE,
            ],
            'priority' => 1,
        ],

        'error' => [
            'middleware' => [
                Catalog\Log\LogMiddleware::class,
            ],
            'error'    => true,
            'priority' => -10000,
        ],
    ],
];

Nevermind the locale wrong path seems to be an expressive FastRoute issue. The urlhelper works fine

Glad to see you found source of this problem!