2016-08-01 8 views
1

Я использую компонент маршрутизации 3.1 Symfony в качестве отдельного компонента.Как отлаживать маршруты с помощью Symfony Routing в качестве отдельного компонента?

Я хочу отладить маршруты.

В соответствии с этим: http://symfony.com/doc/current/routing/debug.html

это делается с помощью следующей команды:

php bin/console debug:router 

Хотя это тривиальное для проекта выполняется полный рамки Symfony, как я запустить его при использовании компонент маршрутизатора как автономный модуль?

ответ

2

Я бы отправил комментарий, но не хватает репутации ..

Во всяком случае, вы должны попытаться потребовать компонент отладки в проекте для того, чтобы использовать его:

$ composer require symfony/debug 

обновление ответа

Хорошо, я сделал некоторые повторно поиск и тестирование, и, наконец, команда отладки маршрутизатора работает. Тем не менее, я все еще использую два компонента symfony, консоль и конфигурацию, но я уверен, что с некоторыми последующими поисками вы можете избежать конфигурации.

Я создал новый проект:

$ composer init 
$ composer require symfony/routing 
$ composer require symfony/console 
$ composer require symfony/config 

Не забудьте автозагрузку исходный код в composer.json:

{ 
    "name": "lolmx/test", 
    "require": { 
     "php": "^5.6", 
     "symfony/console": "^3.1", 
     "symfony/routing": "^3.1", 
     "symfony/config": "^3.1" 
    }, 
    "autoload": { 
     "psr-0": { 
      "": "src/" 
     } 
    } 
} 

Тогда $ composer install.

Создание файла консоли в каталоге проекта $ touch bin/console, и записать его:

<?php 

// Include composer autoloader 
require_once __DIR__."/../vendor/autoload.php"; 

// Use statements 
use Symfony\Component\Config\FileLocator; 
use Symfony\Component\Console\Application; 
use Symfony\Component\Routing\Router; 
use Symfony\Component\Routing\RequestContext; 
use Symfony\Component\Routing\Loader\PhpFileLoader; 
use AppBundle\Command\MyRouterDebugCommand; 

$context = new RequestContext(); 
$locator = new FileLocator(array(__DIR__)); // I needed symfony/config for this 
$router = new Router(
    new PhpFileLoader($locator), // And this class depends upon too 
    '../src/AppBundle/Routes.php', 
    array(), 
    $context 
); 

$app = new Application(); 
$app->add(new MyRouterDebugCommand(null, $router)); 
$app->run(); 
?> 

Я просто инстанцируйте мой маршрутизатор, дать его к моей команде, а также добавить команду в консольном приложении.

Вот что выглядит мой routes.php как:

// src/AppBundle/Routes.php 
<?php 

use Symfony\Component\Routing\RouteCollection; 
use Symfony\Component\Routing\Route; 

$collection = new RouteCollection(); 
$collection->add('name', new Route("/myRoute", array(), array(), array(), "myHost", array('http', 'https'), array('GET', 'PUT'))); 
// more routes added here 

return $collection; 

Теперь напишем саму команду класс:

<?php 

namespace AppBundle\Command; 

use AppBundle\Descriptor\DescriptorHelper; 
use AppBundle\Descriptor\TextDescriptor; 
use Symfony\Component\Console\Command\Command; 
use Symfony\Component\Console\Input\InputArgument; 
use Symfony\Component\Console\Input\InputInterface; 
use Symfony\Component\Console\Input\InputOption; 
use Symfony\Component\Console\Output\OutputInterface; 
use Symfony\Component\Console\Style\SymfonyStyle; 
use Symfony\Component\Routing\Router; 
use Symfony\Component\Routing\RouterInterface; 
use Symfony\Component\Routing\Route; 

class MyRouterDebugCommand extends Command 
{ 
    private $router; 

    public function __construct($name = null, Router $router) 
    { 
     parent::__construct($name); 
     $this->router = $router; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function isEnabled() 
    { 
     if (is_null($this->router)) { 
      return false; 
     } 
     if (!$this->router instanceof RouterInterface) { 
      return false; 
     } 
     return parent::isEnabled(); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    protected function configure() 
    { 
     $this 
      ->setName('debug:router') 
      ->setDefinition(array(
       new InputArgument('name', InputArgument::OPTIONAL, 'A route name'), 
       new InputOption('show-controllers', null, InputOption::VALUE_NONE, 'Show assigned controllers in overview'), 
       new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), 
       new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw route(s)'), 
      )) 
      ->setDescription('Displays current routes for an application') 
      ->setHelp(<<<'EOF' 
The <info>%command.name%</info> displays the configured routes: 
    <info>php %command.full_name%</info> 
EOF 
      ) 
     ; 
    } 

    /** 
    * {@inheritdoc} 
    * 
    * @throws \InvalidArgumentException When route does not exist 
    */ 
    protected function execute(InputInterface $input, OutputInterface $output) 
    { 
     $io = new SymfonyStyle($input, $output); 
     $name = $input->getArgument('name'); 
     $helper = new DescriptorHelper(); 
     if ($name) { 
      $route = $this->router->getRouteCollection()->get($name); 
      if (!$route) { 
       throw new \InvalidArgumentException(sprintf('The route "%s" does not exist.', $name)); 
      } 
      $this->convertController($route); 
      $helper->describe($io, $route, array(
       'format' => $input->getOption('format'), 
       'raw_text' => $input->getOption('raw'), 
       'name' => $name, 
       'output' => $io, 
      )); 
     } else { 
      $routes = $this->router->getRouteCollection(); 
      foreach ($routes as $route) { 
       $this->convertController($route); 
      } 
      $helper->describe($io, $routes, array(
       'format' => $input->getOption('format'), 
       'raw_text' => $input->getOption('raw'), 
       'show_controllers' => $input->getOption('show-controllers'), 
       'output' => $io, 
      )); 
     } 
    } 

    private function convertController(Route $route) 
    { 
     $nameParser = new TextDescriptor(); 
     if ($route->hasDefault('_controller')) { 
      try { 
       $route->setDefault('_controller', $nameParser->build($route->getDefault('_controller'))); 
      } catch (\InvalidArgumentException $e) { 
      } 
     } 
    } 
} 

Imagine вы используете помощник дескриптора по умолчанию use Symfony\Component\Console\Descriptor\DescriptorHelper

$ php bin/console debug:router 

Закончится этой замечательной ошибкой:

[Symfony\Component\Console\Exception\InvalidArgumentException]    
Object of type "Symfony\Component\Routing\RouteCollection" is not describable. 

Хорошо, поэтому нам нужно создать наш пользовательский дескрипторHelper.Первый реализует интерфейс

<?php 

namespace AppBundle\Descriptor; 

use Symfony\Component\Console\Descriptor\DescriptorInterface; 
use Symfony\Component\Console\Output\OutputInterface; 
use Symfony\Component\Routing\Route; 
use Symfony\Component\Routing\RouteCollection; 

abstract class Descriptor implements DescriptorInterface 
{ 
    /** 
    * @var OutputInterface 
    */ 
    protected $output; 
    /** 
    * {@inheritdoc} 
    */ 
    public function describe(OutputInterface $output, $object, array $options = array()) 
    { 
     $this->output = $output; 
     switch (true) { 
      case $object instanceof RouteCollection: 
       $this->describeRouteCollection($object, $options); 
       break; 
      case $object instanceof Route: 
       $this->describeRoute($object, $options); 
       break; 
      case is_callable($object): 
       $this->describeCallable($object, $options); 
       break; 
      default: 
       throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object))); 
     } 
    } 
    /** 
    * Returns the output. 
    * 
    * @return OutputInterface The output 
    */ 
    protected function getOutput() 
    { 
     return $this->output; 
    } 
    /** 
    * Writes content to output. 
    * 
    * @param string $content 
    * @param bool $decorated 
    */ 
    protected function write($content, $decorated = false) 
    { 
     $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); 
    } 
    /** 
    * Describes an InputArgument instance. 
    * 
    * @param RouteCollection $routes 
    * @param array   $options 
    */ 
    abstract protected function describeRouteCollection(RouteCollection $routes, array $options = array()); 
    /** 
    * Describes an InputOption instance. 
    * 
    * @param Route $route 
    * @param array $options 
    */ 
    abstract protected function describeRoute(Route $route, array $options = array()); 
    /** 
    * Describes a callable. 
    * 
    * @param callable $callable 
    * @param array $options 
    */ 
    abstract protected function describeCallable($callable, array $options = array()); 
    /** 
    * Formats a value as string. 
    * 
    * @param mixed $value 
    * 
    * @return string 
    */ 
    protected function formatValue($value) 
    { 
     if (is_object($value)) { 
      return sprintf('object(%s)', get_class($value)); 
     } 
     if (is_string($value)) { 
      return $value; 
     } 
     return preg_replace("/\n\s*/s", '', var_export($value, true)); 
    } 
    /** 
    * Formats a parameter. 
    * 
    * @param mixed $value 
    * 
    * @return string 
    */ 
    protected function formatParameter($value) 
    { 
     if (is_bool($value) || is_array($value) || (null === $value)) { 
      $jsonString = json_encode($value); 
      if (preg_match('/^(.{60})./us', $jsonString, $matches)) { 
       return $matches[1].'...'; 
      } 
      return $jsonString; 
     } 
     return (string) $value; 
    } 
} 

затем переопределить DescriptorHelper по умолчанию зарегистрировать наш дескриптор

<?php 

namespace AppBundle\Descriptor; 

use Symfony\Component\Console\Helper\DescriptorHelper as BaseDescriptorHelper; 

class DescriptorHelper extends BaseDescriptorHelper 
{ 
    /** 
    * Constructor. 
    */ 
    public function __construct() 
    { 
     $this 
      ->register('txt', new TextDescriptor()) 
     ; 
    } 
} 

И, наконец, реализует наш дескриптор

<?php 

namespace AppBundle\Descriptor; 

use Symfony\Component\Console\Helper\Table; 
use Symfony\Component\Routing\Route; 
use Symfony\Component\Routing\RouteCollection; 

class TextDescriptor extends Descriptor 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    protected function describeRouteCollection(RouteCollection $routes, array $options = array()) 
    { 
     $showControllers = isset($options['show_controllers']) && $options['show_controllers']; 
     $tableHeaders = array('Name', 'Method', 'Scheme', 'Host', 'Path'); 
     if ($showControllers) { 
      $tableHeaders[] = 'Controller'; 
     } 
     $tableRows = array(); 
     foreach ($routes->all() as $name => $route) { 
      $row = array(
       $name, 
       $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY', 
       $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY', 
       '' !== $route->getHost() ? $route->getHost() : 'ANY', 
       $route->getPath(), 
      ); 
      if ($showControllers) { 
       $controller = $route->getDefault('_controller'); 
       if ($controller instanceof \Closure) { 
        $controller = 'Closure'; 
       } elseif (is_object($controller)) { 
        $controller = get_class($controller); 
       } 
       $row[] = $controller; 
      } 
      $tableRows[] = $row; 
     } 
     if (isset($options['output'])) { 
      $options['output']->table($tableHeaders, $tableRows); 
     } else { 
      $table = new Table($this->getOutput()); 
      $table->setHeaders($tableHeaders)->setRows($tableRows); 
      $table->render(); 
     } 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    protected function describeRoute(Route $route, array $options = array()) 
    { 
     $tableHeaders = array('Property', 'Value'); 
     $tableRows = array(
      array('Route Name', isset($options['name']) ? $options['name'] : ''), 
      array('Path', $route->getPath()), 
      array('Path Regex', $route->compile()->getRegex()), 
      array('Host', ('' !== $route->getHost() ? $route->getHost() : 'ANY')), 
      array('Host Regex', ('' !== $route->getHost() ? $route->compile()->getHostRegex() : '')), 
      array('Scheme', ($route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY')), 
      array('Method', ($route->getMethods() ? implode('|', $route->getMethods()) : 'ANY')), 
      array('Requirements', ($route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM')), 
      array('Class', get_class($route)), 
      array('Defaults', $this->formatRouterConfig($route->getDefaults())), 
      array('Options', $this->formatRouterConfig($route->getOptions())), 
     ); 
     $table = new Table($this->getOutput()); 
     $table->setHeaders($tableHeaders)->setRows($tableRows); 
     $table->render(); 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    protected function describeCallable($callable, array $options = array()) 
    { 
     $this->writeText($this->formatCallable($callable), $options); 
    } 

    /** 
    * @param array $config 
    * 
    * @return string 
    */ 
    private function formatRouterConfig(array $config) 
    { 
     if (empty($config)) { 
      return 'NONE'; 
     } 
     ksort($config); 
     $configAsString = ''; 
     foreach ($config as $key => $value) { 
      $configAsString .= sprintf("\n%s: %s", $key, $this->formatValue($value)); 
     } 
     return trim($configAsString); 
    } 

    /** 
    * @param callable $callable 
    * 
    * @return string 
    */ 
    private function formatCallable($callable) 
    { 
     if (is_array($callable)) { 
      if (is_object($callable[0])) { 
       return sprintf('%s::%s()', get_class($callable[0]), $callable[1]); 
      } 
      return sprintf('%s::%s()', $callable[0], $callable[1]); 
     } 
     if (is_string($callable)) { 
      return sprintf('%s()', $callable); 
     } 
     if ($callable instanceof \Closure) { 
      return '\Closure()'; 
     } 
     if (method_exists($callable, '__invoke')) { 
      return sprintf('%s::__invoke()', get_class($callable)); 
     } 
     throw new \InvalidArgumentException('Callable is not describable.'); 
    } 

    /** 
    * @param string $content 
    * @param array $options 
    */ 
    private function writeText($content, array $options = array()) 
    { 
     $this->write(
      isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content, 
      isset($options['raw_output']) ? !$options['raw_output'] : true 
     ); 
    } 
} 

Теперь писать вывод $ php bin/console debug:router воли

------ --------- ------------ -------- ---------- 
    Name Method Scheme  Host  Path  
------ --------- ------------ -------- ---------- 
    name GET|PUT http|https myHost /myRoute 
------ --------- ------------ -------- ---------- 

Я погрузился в исходный код symfony, чтобы найти все это, и разные файлы являются/могут быть фрагментами кода от Symfony, symfony routing, console и framework-bundle.

+0

Да, я это требую. Но проблема в том, что у меня даже нет «bin/console», поскольку я не использую полную инфраструктуру Symfony. Просто выберите компоненты. –

+0

Хмм, вы пробовали, чтобы «symfony/console»? – lolmx

+1

@lolmx - Возможно, вам нужно немного исследовать разницу между отдельными компонентами Symfony (такими как компонент маршрутизации) и инфраструктурой Symfony. Фреймворки реализуют команду отладки маршрутизации. Никакая установка отдельных компонентов не приведет к появлению команды отладки маршрутизации. – Cerad

 Смежные вопросы

  • Нет связанных вопросов^_^