2016-08-01 2 views
1

J'utilise le composant de routage 3.1 de Symfony en tant que composant autonome.Comment déboguer des routes à l'aide de Symfony Routing en tant que composant autonome?

Je souhaite déboguer les routes.

Selon ceci: http://symfony.com/doc/current/routing/debug.html

cela se fait en exécutant la commande suivante:

php bin/console debug:router 

Bien que ce soit trivial pour un projet en cours d'exécution pleinement Symfony, comment puis-je l'exécuter lors de l'utilisation le composant du routeur en tant que module autonome?

Répondre

2

J'ai posté un commentaire mais pas assez réputation ..

Quoi qu'il en soit, vous devriez essayer d'exiger le composant de débogage dans votre projet afin de l'utiliser:

$ composer require symfony/debug 

mise à jour de réponse

d'accord, je l'ai fait une re recherche et test, et enfin obtenu la commande de débogage du routeur de travail. Cependant, j'utilise toujours deux composants symfony, console et config, mais je suis sûr qu'avec d'autres recherches, vous pouvez éviter la configuration.

J'ai créé un tout nouveau projet:

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

Ne pas oublier de charger automatiquement votre code source dans le 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/" 
     } 
    } 
} 

Puis $ composer install.

Créer le fichier de la console dans votre répertoire de projet $ touch bin/console, et l'écrire:

<?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(); 
?> 

J'instanciez simplement mon routeur, donner à ma commande, et ajouter la commande à l'application de la console.

Voici ce que mon routes.php ressemble:

// 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; 

Maintenant, nous allons écrire la classe de commande elle-même:

<?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) { 
      } 
     } 
    } 
} 

Imaginez que vous utilisez le descripteur par défaut aide use Symfony\Component\Console\Descriptor\DescriptorHelper

$ php bin/console debug:router 

Termine par cette merveilleuse erreur:

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

Bon, nous avons donc besoin de créer notre DescriptorHelper personnalisé.Tout d'abord implémente l'interface

<?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; 
    } 
} 

Ensuite, remplacer les DescriptorHelper par défaut pour enregistrer notre descripteur

<?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()) 
     ; 
    } 
} 

Et enfin, met en œuvre notre descripteur

<?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 
     ); 
    } 
} 

écrit maintenant $ php bin/console debug:router volonté sortie

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

J'ai plongé dans le code source symfony pour trouver tout cela, et les différents fichiers sont/peuvent être des extraits de code de Symfony, symfony routing, console et framework-bundle.

+0

Oui, je l'ai demandé. Mais le problème est que je n'ai même pas de 'bin/console' car je n'utilise pas le framework complet de Symfony. Sélectionnez simplement les composants. –

+0

Hum, avez-vous essayé d'exiger 'symfony/console'? – lolmx

+1

@lolmx - Peut-être souhaitez-vous rechercher un peu la différence entre les composants Symfony individuels (tels que le composant de routage) et le framework Symfony. Les frameworks implémentent la commande de débogage de routage. Aucune quantité d'installation de composants individuels ne va faire apparaître la commande de débogage de routage. – Cerad