Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Api/Docs/Compiler.php
<?php

namespace XF\Api\Docs;

use
XF\Api\Docs\Renderer\RendererInterface;

class
Compiler
{
   
/**
     * @var AnnotationParser
     */
   
protected $annotationParser;

   
/**
     * @var ClassParser
     */
   
protected $classParser;

   
/**
     * @var Annotation\RouteBlock[][]
     */
   
protected $routesByAddOn = [];

   
/**
     * @var Annotation\TypeBlock[]
     */
   
protected $types = [];

    public static
$methodSortOrder = [
       
'GET' => 0,
       
'POST' => 1,
       
'PUT' => 2,
       
'PATCH' => 3,
       
'DELETE' => 4
   
];

    public function
__construct(AnnotationParser $annotationParser, ClassParser $classParser)
    {
       
$annotationParser->setClassParser($classParser);

       
$this->annotationParser = $annotationParser;
       
$this->classParser = $classParser;
    }

    public function
compileForAddOn($addOnId)
    {
       
$ds = \XF::$DS;

       
// add-on IDs use a forward slash (not a backslash), so standardize
       
$addOnId = str_replace('\\', '/', $addOnId);

        if (
$addOnId == 'XF')
        {
           
$baseDir = \XF::getSourceDirectory() . $ds . 'XF';
        }
        else
        {
           
$baseDir = \XF::getAddOnDirectory() . $ds . str_replace('/', $ds, $addOnId);
        }

       
$entityDir = "{$baseDir}{$ds}Entity";
        if (
file_exists($entityDir))
        {
           
$classPrefix = str_replace('/', '\\', $addOnId);

            foreach (new \
DirectoryIterator($entityDir) AS /** @var \DirectoryIterator $file */ $file)
            {
                if (
$file->getExtension() == 'php')
                {
                   
$entityName = $classPrefix . ':' . substr($file->getBasename(), 0, -4);
                   
$typeBlock = $this->classParser->parseEntityClass($entityName);
                    if (
$typeBlock)
                    {
                       
$this->types[$typeBlock->type] = $typeBlock;
                    }
                }
            }
        }

       
$this->routesByAddOn[$addOnId] = [];

       
$apiRoutes = \XF::db()->fetchAll("
            SELECT route_prefix, format, controller
            FROM xf_route
            WHERE route_type = 'api'
                AND addon_id = ?
        "
, $addOnId);
        foreach (
$apiRoutes AS $route)
        {
           
$controllerRoutes = $this->classParser->parseControllerClass(
               
$route['controller'],
               
$this->getRouteUrl($route['route_prefix'], $route['format'])
            );
           
$this->routesByAddOn[$addOnId] = array_merge($this->routesByAddOn[$addOnId], $controllerRoutes);
        }
    }

    protected function
getRouteUrl($prefix, $format)
    {
       
$extra = $format;

       
$extra = preg_replace(
           
'#:(\+)?int(?:_p)?<([a-zA-Z0-9_]+)(?:,[a-zA-Z0-9_]+)?>/?#',
           
'{$2}/',
           
$extra
       
);

       
$extra = preg_replace(
           
'#:(\+)?str(?:_p)?<([a-zA-Z0-9_]+)>/?#',
           
'{$2}/',
           
$extra
       
);

       
$extra = preg_replace(
           
'#:page<([a-zA-Z0-9_]+)>/?#',
           
'page-{page}',
           
$extra
       
);
       
$extra = preg_replace(
           
'#:page/?#',
           
'page-{page}',
           
$extra
       
);

       
$extra = preg_replace(
           
'#:(\+)?any<([a-zA-Z0-9_]+)>/?#',
           
'{$2}/',
           
$extra
       
);

       
// simplify names to "id" if they end in _id
       
$extra = preg_replace(
           
'#\{[a-zA-Z0-9_]+_id\}#',
           
'{id}',
           
$extra
       
);

        return
$prefix . '/' . $extra;
    }

    public function
getRoutesFlattened()
    {
       
$routes = [];
        foreach (
$this->routesByAddOn AS $addOnRoutes)
        {
            foreach (
$addOnRoutes AS $k => $v)
            {
               
$routes[$k] = $v;
            }
        }

        return
$this->sortRoutes($routes);
    }

    public function
getRoutesByGroup()
    {
       
$routeGroupings = [];

        foreach (
$this->routesByAddOn AS $addOnRoutes)
        {
            foreach (
$addOnRoutes AS $k => $route)
            {
               
$group = $route->group ?: 'ungrouped';
               
$routeGroupings[$group][$k] = $route;
            }
        }

        return
$this->sortRoutesGrouped($routeGroupings);
    }

    public function
getRoutesByAddOn()
    {
        return
$this->routesByAddOn;
    }

    public function
getRoutesForAddOn($addOnId)
    {
        return
$this->routesByAddOn[$addOnId] ?? [];
    }

    public function
addOnHasRoutes($addOnId)
    {
        return isset(
$this->routesByAddOn[$addOnId]);
    }

    public function
getTypes()
    {
        return
$this->types;
    }

   
/**
     * @param Annotation\RouteBlock[] $routes
     *
     * @return Annotation\RouteBlock[]
     */
   
public function sortRoutes(array $routes)
    {
       
uasort($routes, function(Annotation\RouteBlock $r1, Annotation\RouteBlock $r2)
        {
            if (
$r1->route !== $r2->route)
            {
                return (
$r1->route < $r2->route ? -1 : 1);
            }

           
$r1Order = self::$methodSortOrder[$r1->method] ?? 100;
           
$r2Order = self::$methodSortOrder[$r2->method] ?? 100;

            if (
$r1Order === $r2Order)
            {
                return
0;
            }
            return (
$r1Order < $r2Order ? -1 : 1);
        });

        return
$routes;
    }

   
/**
     * @param Annotation\RouteBlock[][] $routesGrouped
     *
     * @return Annotation\RouteBlock[][]
     */
   
public function sortRoutesGrouped(array $routesGrouped)
    {
        foreach (
$routesGrouped AS &$routes)
        {
           
$routes = $this->sortRoutes($routes);
        }

        return
$routesGrouped;
    }

    public function
render(RendererInterface $renderer)
    {
        return
$renderer->render($this->getRoutesByGroup(), $this->types);
    }
}