Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Cli/Command/Development/GeneratePhpStormMeta.php
<?php

namespace XF\Cli\Command\Development;

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;

class
GeneratePhpStormMeta extends Command
{
    use
RequiresDevModeTrait;

    protected function
configure()
    {
       
$this
           
->setName('xf-dev:generate-phpstorm-meta')
            ->
setDescription('Generates a .phpstorm.meta.php file for dynamic return type hinting')
            ->
addArgument(
               
'path',
               
InputArgument::OPTIONAL,
               
'Path to save the generated .phpstorm.meta.php file.',
               
'.phpstorm.meta.php'
           
)
            ->
addOption(
               
'print',
               
null,
               
InputOption::VALUE_NONE,
               
'If enabled, prints instead of writing'
           
);
    }

    protected function
execute(InputInterface $input, OutputInterface $output)
    {
       
$staticMethodTypes = '';
       
$definitions = $this->getMetaDefinitions();
       
$searchPaths = $this->getSearchPaths();

        foreach (
$definitions AS $type => $definition)
        {
           
$classes = '';

            foreach (
$searchPaths AS $addOnId => $filePath)
            {
               
$searchDir = sprintf(
                   
str_replace('\\', \XF::$DS, $definition['format']),
                   
$filePath,
                   
''
               
);
                if (!
file_exists($searchDir) || !is_dir($searchDir))
                {
                    continue;
                }

               
$iterator = new \RegexIterator(
                    \
XF\Util\File::getRecursiveDirectoryIterator($searchDir, null, null), '/\.php$/'
               
);

               
/** @var \SplFileInfo $file */
               
foreach ($iterator AS $name => $file)
                {
                   
$suffixClass = str_replace($searchDir, '', $file->getRealPath());
                   
$suffixClass = str_replace('.php', '', $suffixClass);
                   
$suffixClass = trim(str_replace(\XF::$DS, '\\', $suffixClass), '\\');
                   
$fqClass = sprintf($definition['format'], "\\{$addOnId}", $suffixClass);

                    if (!
class_exists($fqClass))
                    {
                        continue;
                    }

                   
$reflection = new \ReflectionClass($fqClass);
                    if (
$reflection->isAbstract() || $reflection->isInterface() || $reflection->isTrait())
                    {
                        continue;
                    }

                   
$shortClass = "{$addOnId}:{$suffixClass}";
                   
$classes .= ($classes ? ",\n" : "\n") . "\t\t'{$shortClass}' => {$fqClass}::class";
                }
            }

           
$staticMethodTypes .= "\t// $type\n";
            foreach (
$definition['methods'] AS $method)
            {
               
$staticMethodTypes .= <<< STATICMETHODTYPES
\toverride($method, map([$classes\n\t]));\n
STATICMETHODTYPES;

            }
        }

       
$staticMethodTypes = rtrim($staticMethodTypes, ",\n");

       
$fileOutput = <<< METAOUT
<?php

namespace PHPSTORM_META
{
{$staticMethodTypes}
}
METAOUT;

        if (
$input->getOption('print'))
        {
           
$output->writeln($fileOutput);
        }
        else
        {
           
$path = $input->getArgument('path');
           
$dir = dirname($path);

           
$output->writeln("Writing $path...");

            if (!
is_writable($dir))
            {
               
$output->writeln("File could not be written to. Check directories exist and permissions.");
                return
5;
            }

           
file_put_contents($path, $fileOutput);
           
$output->writeln("Written successfully.");
        }

        return
0;
    }

    protected function
getMetaDefinitions()
    {
        return [
           
'Behavior' => [
               
'format' => '%s\Behavior\%s',
               
'methods' => [
                   
'\XF\Mvc\Entity::getBehavior(0)'
               
]
            ],
           
'ControllerPlugin' => [
               
'format' => '%s\ControllerPlugin\%s',
               
'methods' => [
                   
'\XF\Mvc\Controller::plugin(0)'
               
],
               
'default' => '\XF\ControllerPlugin\AbstractPlugin'
           
],
           
'Data' => [
               
'format' => '%s\Data\%s',
               
'methods' => [
                   
'\XF\App::data(0)',
                   
'\XF\Mvc\Controller::data(0)'
               
]
            ],
           
'Entity' => [
               
'format' => '%s\Entity\%s',
               
'methods' => [
                   
'\XF\Mvc\Entity\Manager::create(0)',
                   
'\XF\Mvc\Entity\Manager::find(0)',
                   
'\XF\Mvc\Entity\Manager::findOne(0)',
                   
'\XF\Mvc\Controller::assertRecordExists(0)'
               
]
            ],
           
'Finder' => [
               
'format' => '%s\Finder\%s',
               
'methods' => [
                   
'\XF::finder(0)',
                   
'\XF\App::finder(0)',
                   
'\XF\AddOn\DataType\AbstractDataType::finder(0)',
                   
'\XF\Mvc\Controller::finder(0)',
                   
'\XF\Mvc\Entity\Entity::finder(0)',
                   
'\XF\Mvc\Entity\Manager::getFinder(0)',
                   
'\XF\Mvc\Entity\Repository::finder(0)',
                   
'\XF\Searcher\AbstractSearcher::getFinder(0)',
                   
'\XF\Service\AbstractService::finder(0)',
                   
'\XF\Widget\AbstractWidget::finder(0)'
               
],
               
'default' => '\XF\Mvc\Entity\Finder'
           
],
           
'Repository' => [
               
'format' => '%s\Repository\%s',
               
'methods' => [
                   
'\XF::repository(0)',
                   
'\XF\App::repository(0)',
                   
'\XF\Mvc\Controller::repository(0)',
                   
'\XF\Mvc\Entity\Behavior::repository(0)',
                   
'\XF\Mvc\Entity\Entity::repository(0)',
                   
'\XF\Mvc\Entity\Manager::getRepository(0)',
                   
'\XF\Mvc\Entity\Repository::repository(0)',
                   
'\XF\Service\AbstractService::repository(0)',
                   
'\XF\Widget\AbstractWidget::repository(0)'
               
]
            ],
           
'Searcher' => [
               
'format' => '%s\Searcher\%s',
               
'methods' => [
                   
'\XF\App::searcher(0)'
               
],
               
'default' => '\XF\Searcher\AbstractSearcher'
           
],
           
'Service' => [
               
'format' => '%s\Service\%s',
               
'methods' => [
                   
'\XF::service(0)',
                   
'\XF\App::service(0)',
                   
'\XF\Mvc\Controller::service(0)',
                   
'\XF\Service\AbstractService::service(0)',
                   
'\XF\Widget\AbstractWidget::service(0)'
               
],
               
'default' => '\XF\Service\AbstractService'
           
],
           
'Validator' => [
               
'format' => '%s\Validator\%s',
               
'methods' => [
                   
'\XF\App::validator(0)'
               
],
               
'default' => '\XF\Validator\AbstractValidator'
           
]
        ];
    }

    protected function
getSearchPaths()
    {
       
$paths = [
           
'XF' => \XF::getSourceDirectory() . \XF::$DS . 'XF'
       
];
       
$addOnManager = \XF::app()->addOnManager();

        foreach (
$addOnManager->getAvailableAddOnIds() AS $addOnId)
        {
            if (
$addOnId == 'XF')
            {
                continue;
            }

           
$paths[str_replace('/', '\\', $addOnId)] = $addOnManager->getAddOnPath($addOnId);
        }

        return
$paths;
    }
}