How to get the base url Programatically in zend expressive?

expressive

#1

I am working on an API application that will be run in different domains: http://example.com/, http://sub.example.com/, http://example-another.com/. Part of the API responses needs to send out its base_url. So I am trying to find a way to dynamically collect the base_url and add it to my response.

I have a factory to initiate the action handler as follows:

class TestHandlerFactory
{
    public function __invoke(ContainerInterface $container) : TestHandler
    {
        
        return new TestHandler();
    }
}

Then my action handler is as follows:

class TestHandler implements RequestHandlerInterface
{
    public function __construct()
    {
        ...
    }
    public function handle(ServerRequestInterface $request) : ResponseInterface
    {
        
       ...
    }
}

I am new to Zend world and I found the https://github.com/zendframework/zend-http/blob/master/src/PhpEnvironment/Request.php probably a potential solution of my problem. However, I do not how to get that PHP-Environment object (or any other object that help me grab the base url) in the factory or handler class.


#2

Expressive uses PSR-7, which is a very different abstraction than zend-http. By default, we use Diactoros, which is our PSR-7 implementation (and the one in widest use in the PHP ecosystem).

However, to answer your question more directly, PSR-7 is neither here nor there. What you need in this case is the ServerUrlHelper. Compose this helper in your handler:

use Zend\Expressive\Helper\ServerUrlHelper;

class TestHandler implements RequestHandlerInterface
{
    private $serverUrlHelper;

    public function __construct(ServerUrlHelper $serverUrlHelper)
    {
        $this->serverUrlHelper = $serverUrlHelper;
    }

    public function handle(ServerRequestInterface $request) : ResponseInterface
    {
        $baseUrl = $this->serverUrlHelper->generate();
        // ...
    }
}

and then update your factory to inject it:

use Zend\Expressive\Helper\ServerUrlHelper;

class TestHandlerFactory
{
    public function __invoke(ContainerInterface $container)
    {
        return new TestHandler($container->get(ServerUrlHelper::class));
    }
}

By default, we place the ServerUrlHelperMiddleware in the application pipeline, and that middleware will inspect the request to get its Uri instance, and push that into the ServerUrlHelper, so that the above will correctly give you the base URL (which will include the scheme, host, and, if on a non-standard port, the port.


#3

Thanks for your reply. This one is giving me the full url, not the base url. For example: i have a route http://sub.domain.com/install where I need to send out the base url (http://sub.domain.com/). The generate() is including the /install in outs output. Is there any way I get get the base_url directly. I can certainly do the string operations, but I am kin to know the right way, if there is one.


#4

Can you show me how you’re calling generate(), please?

If there is a URI instance present in the ServerUrlHelper, it uses that instance to generate the URL string. The logic is such that if you do not pass an argument to the generate() method, or an empty string, it will use the full URI instance, including path, to generate the string URL.

The way around it is to pass a single slash to it: $url = $this->serverUrl->generate('/');

Doing so will give you the scheme + authority only, which, based on your original post, is what you want.


#5

Thanks,
The workaround works well. My application is currently setup in the root of the domain. Will have to test how it behavs when i will have to set it up in the subfolder. But thanks a lot.