<commit_before><?php

/*
 * This file is part of the NelmioApiDocBundle.
 *
 * (c) Nelmio <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nelmio\ApiDocBundle\Extractor;

use Doctrine\Common\Annotations\Reader;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;

class ApiDocExtractor
{
    const ANNOTATION_CLASS = 'Nelmio\\ApiDocBundle\\Annotation\\ApiDoc';

    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;

    /**
     * @var \ymfony\Component\Routing\RouterInterface
     */
    private $router;

    /**
     * @var \Doctrine\Common\Annotations\Reader
     */
    private $reader;

    public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader)
    {
        $this->container = $container;
        $this->router = $router;
        $this->reader = $reader;
    }

    /**
     * Returns an array of data where each data is an array with the following keys:
     *  - annotation
     *  - route
     *  - resource
     *
     * @return array
     */
    public function all()
    {
        $array = array();
        $resources = array();

        foreach ($this->router->getRouteCollection()->all() as $route) {
            $method = false;
            if (preg_match('#(.+)::([\w]+)#', $route->getDefault('_controller'), $matches)) {
                $method = new \ReflectionMethod($matches[1], $matches[2]);
            } elseif (preg_match('#(.+):([\w]+)#', $route->getDefault('_controller'), $matches)) {
                $controller = $matches[1];
                if ($this->container->has($controller)) {
                    $this->container->enterScope('request');
                    $this->container->set('request', new Request);
                    $class = get_class($this->container->get($controller));
                    $this->container->leaveScope('request');
                    $method = new \ReflectionMethod($class, $matches[2]);
                }
            }

            if ($method) {
                $annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS);
                if ($annot) {
                    if ($annot->isResource()) {
                        $resources[] = $route->getPattern();
                    }

                    $array[] = array('annotation' => $annot, 'route' => $route);
                }
            }
        }

        rsort($resources);
        foreach ($array as $index => $element) {
            $hasResource = false;
            $pattern = $element['route']->getPattern();

            foreach ($resources as $resource) {
                if (0 === strpos($pattern, $resource)) {
                    $array[$index]['resource'] = $resource;

                    $hasResource = true;
                    break;
                }
            }

            if (false === $hasResource) {
                $array[$index]['resource'] = 'others';
            }
        }

        $methodOrder = array('GET', 'POST', 'PUT', 'DELETE');

        usort($array, function($a, $b) use ($methodOrder) {
            if ($a['resource'] === $b['resource']) {
                if ($a['route']->getPattern() === $b['route']->getPattern()) {
                    $methodA = array_search($a['route']->getRequirement('_method'), $methodOrder);
                    $methodB = array_search($b['route']->getRequirement('_method'), $methodOrder);

                    if ($methodA === $methodB) {
                        return strcmp($a['route']->getRequirement('_method'), $b['route']->getRequirement('_method'));
                    }

                    return $methodA > $methodB ? 1 : -1;
                }

                return strcmp($a['route']->getPattern(), $b['route']->getPattern());
            }

            return strcmp($a['resource'], $b['resource']);
        });

        return $array;
    }

    /**
     * Returns an array containing two values with the following keys:
     *  - annotation
     *  - route
     *
     * @param string $controller
     * @param Route $route
     * @return array|null
     */
    public function get($controller, $route)
    {
        if (!preg_match('#(.+)::([\w]+)#', $controller, $matches)) {
            return null;
        }

        try {
            $method = new \ReflectionMethod($matches[1], $matches[2]);
        } catch (\ReflectionException $e) {
            return null;
        }

        if ($annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS)) {
            if ($route = $this->router->getRouteCollection()->get($route)) {
                return array('annotation' => $annot, 'route' => $route);
            }
        }

        return null;
    }
}
<commit_msg>also support services as controller in ApiDocExtractor::get()<commit_after><?php

/*
 * This file is part of the NelmioApiDocBundle.
 *
 * (c) Nelmio <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Nelmio\ApiDocBundle\Extractor;

use Doctrine\Common\Annotations\Reader;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;

class ApiDocExtractor
{
    const ANNOTATION_CLASS = 'Nelmio\\ApiDocBundle\\Annotation\\ApiDoc';

    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;

    /**
     * @var \ymfony\Component\Routing\RouterInterface
     */
    private $router;

    /**
     * @var \Doctrine\Common\Annotations\Reader
     */
    private $reader;

    public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader)
    {
        $this->container = $container;
        $this->router = $router;
        $this->reader = $reader;
    }

    /**
     * Returns an array of data where each data is an array with the following keys:
     *  - annotation
     *  - route
     *  - resource
     *
     * @return array
     */
    public function all()
    {
        $array = array();
        $resources = array();

        foreach ($this->router->getRouteCollection()->all() as $route) {
            $method = $this->getReflectionMethod($route->getDefault('_controller'));

            if ($method) {
                $annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS);
                if ($annot) {
                    if ($annot->isResource()) {
                        $resources[] = $route->getPattern();
                    }

                    $array[] = array('annotation' => $annot, 'route' => $route);
                }
            }
        }

        rsort($resources);
        foreach ($array as $index => $element) {
            $hasResource = false;
            $pattern = $element['route']->getPattern();

            foreach ($resources as $resource) {
                if (0 === strpos($pattern, $resource)) {
                    $array[$index]['resource'] = $resource;

                    $hasResource = true;
                    break;
                }
            }

            if (false === $hasResource) {
                $array[$index]['resource'] = 'others';
            }
        }

        $methodOrder = array('GET', 'POST', 'PUT', 'DELETE');

        usort($array, function($a, $b) use ($methodOrder) {
            if ($a['resource'] === $b['resource']) {
                if ($a['route']->getPattern() === $b['route']->getPattern()) {
                    $methodA = array_search($a['route']->getRequirement('_method'), $methodOrder);
                    $methodB = array_search($b['route']->getRequirement('_method'), $methodOrder);

                    if ($methodA === $methodB) {
                        return strcmp($a['route']->getRequirement('_method'), $b['route']->getRequirement('_method'));
                    }

                    return $methodA > $methodB ? 1 : -1;
                }

                return strcmp($a['route']->getPattern(), $b['route']->getPattern());
            }

            return strcmp($a['resource'], $b['resource']);
        });

        return $array;
    }

    /**
     * Returns the ReflectionMethod for the given controller string
     *
     * @param string $controller
     * @return ReflectionMethod|null
     */
    public function getReflectionMethod($controller)
    {
        if (preg_match('#(.+)::([\w]+)#', $controller, $matches)) {
            $class = $matches[1];
            $method = $matches[2];
        } elseif (preg_match('#(.+):([\w]+)#', $controller, $matches)) {
            $controller = $matches[1];
            $method = $matches[2];
            if ($this->container->has($controller)) {
                $this->container->enterScope('request');
                $this->container->set('request', new Request);
                $class = get_class($this->container->get($controller));
                $this->container->leaveScope('request');
            }
        }

        if (isset($class) && isset($method)) {
            try {
                return new \ReflectionMethod($class, $method);
            } catch (\ReflectionException $e) {
            }
        }

        return null;
    }

    /**
     * Returns an array containing two values with the following keys:
     *  - annotation
     *  - route
     *
     * @param string $controller
     * @param Route $route
     * @return array|null
     */
    public function get($controller, $route)
    {
        $method = $this->getReflectionMethod($controller);
        if (!$method) {
            return null;
        }

        if ($annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS)) {
            if ($route = $this->router->getRouteCollection()->get($route)) {
                return array('annotation' => $annot, 'route' => $route);
            }
        }

        return null;
    }
}

{'fraction_non_alphanumeric': 0.15449881610102603, 'fraction_numerical': 0.0015785319652722968, 'mean_word_length': 1.8896807297605474, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 92, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7221941', 'n_tokens_mistral': 2778, 'n_tokens_neox': 2669, 'n_words': 563}