http icon indicating copy to clipboard operation
http copied to clipboard

Cli - Deault domain/host - for generating routes

Open nakashu opened this issue 10 years ago • 9 comments

Current Nette\Http\RequestFactory doesnt support adding default domain for the request

Problems starts when we need to generate links, after executing the script in CLI eg.:

    MyCliPresenter->generateLinksAction() {
        echo $this->link('Homepage:default');
    }
    // outputs:  http:/// 

Whole problem could be solved by adding support for default values for domain and adding a bit of code for using them inside RequestFactory::createHttpRequest() method

        ...
        // after line 94 add
        // use default host, if we didnt get any from $SERVER.
        if (!$url->host)
        {
            $url->host = $this->domain;
        }

this->domain should be populated by setter function, with DI in setup

Another sollution is to use change RequestFactory to be easily extendebale, currently if we want to override createHttpRequest(), with own implementation, it fail when when the script tries to write to $this->binary as there is private access on the variable. For easier extendebility createHttpRequest should be split to smaller pieces. eg. process Query, Hostnamem, Scheme, Binary, etc.

Bellow are 2 current solutions for the problem,

  1. create own HttpRequest and add it as service instead of one generated by factory
  2. change service for httpRequestFactory and HttpRequest for own classes.

bootstrap.php:

    ...
    /**
     * @param \Nette\Configurator $configurator
     * @param \Nette\DI\Compiler $compiler
     */
    $configurator->onCompile[] = function($configurator, $compiler)
    {
        $compiler->addExtension('cli_http', new CliModule\Http\CliHttpRequestExtension());
    };
    ...

CliHttpRequestExtension.php

    namespace CliModule\Http;

    use Nette\DI\CompilerExtension;
    use Nette\DI\Container;
    use Nette\DI\ContainerBuilder;
    use Nette\DI\ServiceDefinition;
    use Nette\Http\Request;
    use Nette\Http\UrlScript;
    use Nette\Utils\Strings;

    class CliHttpRequestExtension extends CompilerExtension
    {
        public function loadConfiguration()
        {
            $container = $this->getContainerBuilder();
            $config    = $this->getConfig();


            /** @var ContainerBuilder $container */
            if ($container->parameters['consoleMode']) {
                // ** variant 1 - create own Request object
                $url = new UrlScript();
                $url->setHost($container->parameters['domain']);
                $url->setScheme('http');

                $arguments = [
                    'url'           => $url,
                    'query'         => NULL,
                    'post'          => NULL,
                    'files'         => NULL,
                    'cookies'       => NULL,
                    'headers'       => NULL,
                    'method'        => NULL,
                    'remoteAddress' => NULL,
                    'remoteHost'    => NULL
                ];

                $container->removeDefinition('httpRequest');
                $container->addDefinition('httpRequest')->setClass('\Nette\Http\Request', $arguments);

                // ** varianta 2- use own RequestFactory **
    //            $container->removeDefinition('httpRequestFactory');
    //            $container->addDefinition('httpRequestFactory')
    //                ->setClass('CliModule\Http\CliRequestFactory')
    //                ->addSetup('setDomain', array($container->parameters['domain']));
    //
    //            $container->getDefinition('httpRequest')
    //                ->setFactory('@CliModule\\CliRequestFactory::createHttpRequest');
    //
            }
        }

    }

CliRequestFactory.php - direct copy of Request factory except added part after line 94

     ...
     public function createHttpRequest()
    {
        // DETECTS URI, base path and script path of the request.
        $url = new UrlScript;
        $url->scheme = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https' : 'http';
        $url->user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
        $url->password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';

        // host & port
        if ((isset($_SERVER[$tmp = 'HTTP_HOST']) || isset($_SERVER[$tmp = 'SERVER_NAME']))
            && preg_match('#^([a-z0-9_.-]+|\[[a-f0-9:]+\])(:\d+)?\z#i', $_SERVER[$tmp], $pair)
        ) {
            $url->host = strtolower($pair[1]);
            if (isset($pair[2])) {
                $url->port = (int) substr($pair[2], 1);
            } elseif (isset($_SERVER['SERVER_PORT'])) {
                $url->port = (int) $_SERVER['SERVER_PORT'];
            }
        }

        // Default vyplnenie Host-u
        if (!$url->host)
        {
            $url->host = $this->domain;
        }
        ...

nakashu avatar Jan 28 '15 13:01 nakashu

I agree that this problem should be addressed, but I think this is a wrong place. If I'm not mistaken, the only thing needed is to make sure that router always gets reasonable $refUrl, so there should be some kind of default fallback value in CLI mode.

xificurk avatar Jan 28 '15 14:01 xificurk

Ahh .. somehow missed that it can be fixed with that ... damn :) Anyway forgot to mention, that problem only exists if you try to generate absolute Url.

nakashu avatar Jan 28 '15 15:01 nakashu

Why don't you use nextras/link-factory?

JanTvrdik avatar Jan 29 '15 00:01 JanTvrdik

@JanTvrdik Because it has all the same problems in CLI as any other Nette router.

xificurk avatar Jan 29 '15 08:01 xificurk

I think we can close it, because it's easy to setup http.url address in CLI directly or via extension.

$builder->getDefinition('http.request')
              ->setClass(Request::class, [new Statement(UrlScript::class, ['https://my.url'])]);

Right @dg @JanTvrdik @xificurk ?

f3l1x avatar Jun 16 '17 20:06 f3l1x

@f3l1x No, HTTP request should not be a service... See the discussion on the public Slack.

Majkl578 avatar Jun 16 '17 20:06 Majkl578

@Majkl578 Well, it's pretty cool, but in nette 2.4 and lower there is httpRequest as service, so I've posted a hint how to do it.

This issue is not about to make httpService non-service.

f3l1x avatar Jun 16 '17 22:06 f3l1x

I disagree with closing this. There should be a configurable default for cli. http://symfony.com/doc/current/console/request_context.html

fprochazka avatar Jun 17 '17 11:06 fprochazka

I see your point @fprochazka. Should I prepare a PR?

http:
    url: nette.org 
http:
    cli: nette.org 

Or something like that?

f3l1x avatar Jun 18 '17 12:06 f3l1x