alex-5zi/hexlet-psr-linter

View on GitHub
src/CLI.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

namespace hexletPsrLinter;

use hexletPsrLinter\Exceptions\CLIException;
use hexletPsrLinter\Linter;
use hexletPsrLinter\Reporter\Reporter;
use League\CLImate\CLImate;
use hexletPsrLinter\Linter\Rules\AutoLoadRules;
use Symfony\Component\Yaml\Yaml;

class CLI
{
    private $fix = false;
    private $files = array();
    private $rules = array();
    private $args;
    private $climate;
    private $report;
    private $reportFormat = 'text';

    public function __construct($name = 'root')
    {
        $this->climate = new CLImate;
        $this->climate->output->defaultTo('buffer');
        $this->climate->arguments->add([
          'fix' => [
              'prefix'       => 'f',
              'longPrefix'   => 'fix',
              'description'  => 'fix',
              'noValue'      => true,
          ],
          'report-format' => [
              'longPrefix'   => 'report-format',
              'description'  => 'text, json, yaml',
          ],
          'rules' => [
              'longPrefix'  => 'rules',
              'description' => 'rules',
          ],
          'help' => [
              'prefix'       => 'h',
              'longPrefix'  => 'help',
              'description' => 'Prints a usage statement',
              'noValue'     => true,
          ],
          'path' => [
              'description' => 'path',
          ],
        ]);
        $this->climate->description('hexlet-psr-linter');
        $this->register();
    }

    public function register()
    {
        spl_autoload_register(
            function ($class) {
                $paths = AutoLoadRules::getRules();
                $name = substr($class, 29);
                if (is_string($name)) {
                    if (array_key_exists($name, $paths)) {
                        $file = $paths[$name];
                        if (file_exists($file)) {
                            require $file;
                        }
                    }
                }
            }
        );
    }

    public function getFiles()
    {
        return $this->files;
    }

    public function getRules()
    {
        return $this->rules;
    }

    public function getFix()
    {
        return $this->fix;
    }

    private function scanpath($path)
    {
        if (is_dir($path)) {
//            $files = scandir($path);
            $paths = [];
//            foreach ($files as $file) {
//                if (substr($file, -4) === '.php') {
//                    $patchs[] = $file;
//                }
            $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
            $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
            foreach ($iterator as $info) {
                if ($info->isFile() && $info->getExtension() == 'php') {
                    array_push($paths, $info->getPathname());
                }
            }

            //  }
            return  $paths;  //glob($path.DIRECTORY_SEPARATOR.'*.php');
        } elseif (is_file($path)) {
            return [$path] ;
        }

        $output  = "ERROR: File or folder \"$path\" not found".PHP_EOL.PHP_EOL;
        $output .= $this->printUsage();
        throw new CLIException($output, 3);
    }

    public function run()
    {
        $this->args = $_SERVER['argv'];
        try {
            $this->setCommandLineValues();
        } catch (CLIException $e) { //(CLIException $e)
            fwrite(STDERR, $e->getMessage());
            return $e->getCode();
        }//end try

        //AutoLoadRules::scanRules();
        foreach ($this->rules as $key => $path) {
            AutoLoadRules::addRules($path);
        }

        foreach ($this->files as $path) {
            if (is_file($path)) {
                $code = file_get_contents($path);
                $code = Linter\lint($code, $path, $this->fix);
                if ($this->fix) {
                    file_put_contents($path, $code);
                }
            }
        }

        $this->report  = Reporter::getReporter()->getReport();

        switch ($this->reportFormat) {
            case 'text':
                if (!empty($this->report)) {
                    foreach ($this->report as $key => $value) {
                        if (!empty($value)) {
                            //  $climate->comment($key);
                            $arrLog = [];
                            $arrLog[] = [$value['level'],
                                      implode(" : ", $value['context']),
                                      $value['message']
                                    ];
                            $this->climate->to('buffer')->columns($arrLog);
                        }
                    }
                }
                break;
            case 'json':
                if (!empty($this->report)) {
                    $this->climate->to('buffer')->json($this->report);
                }
                break;
            case 'yaml':
                if (!empty($this->report)) {
                    $yaml = Yaml::dump($this->report);
                    $this->climate->to('buffer')->out($yaml);
                }
                break;
        }
        $out = $this->climate->output->get('buffer')->get();

        fwrite(STDOUT, $out);
    }


    private function setCommandLineValues()
    {
        array_shift($this->args);

        $numArgs = count($this->args);

        if ($numArgs == 0) {
            throw new CLIException($this->printUsage(), 0);
        }
        for ($i = 0; $i < $numArgs; $i++) {
            $arg = $this->args[$i];
            if ($arg === '') {
                continue;
            }
            if ($arg{0} === '-') {
                if ($arg === '-' || $arg === '--') {
                    continue;
                }
                if ($arg{1} === '-') {
                    $i = $this->processArgument(substr($arg, 2), $i);
                } else {
                    $switches = str_split($arg);
                    foreach ($switches as $switch) {
                        if ($switch === '-') {
                            continue;
                        }
                        $i = $this->processArgument($switch, $i);
                    }
                }
            } else {
                $this->processUnknownArgument($arg, $i);
            } //end if
        } //end for
    }

    private function processArgument($arg, $pos)
    {
        switch ($arg) {
            case 'h':
            case '?':
            case 'help':
                $output = $this->printUsage();
                throw new CLIException($output, 0);
            case 'f':
            case 'fix':
                $this->fix = true;
                break;
            case 'rules':
                $pos++;
                if (isset($this->args[($pos)]) === false) {
                    $output = 'ERROR: Setting a rules option requires a value'.PHP_EOL.PHP_EOL;
                    $output .= $this->printUsage();
                    throw new CLIException($output, 3);
                } //end if
                $value   = $this->args[($pos)];
                $this->rules = array_merge($this->rules, $this->scanpath($value));
                break;
            case 'report-format':
                $pos++;
                if (isset($this->args[($pos)]) === false) {
                    $output = 'ERROR: Setting a report-format option requires a value'.PHP_EOL.PHP_EOL;
                    $output .= $this->printUsage();
                    throw new CLIException($output, 3);
                } //end if
                $value   = $this->args[($pos)];
                if ($value === 'text' || $value === 'json' || $value === 'yaml') {
                    $this->reportFormat = $value;
                } else {
                    $output = 'ERROR: Setting a report-format option requires a value'.PHP_EOL.PHP_EOL;
                    $output .= $this->printUsage();
                    throw new CLIException($output, 3);
                }
                break;
            default:
                $output  = "ERROR: option \"$arg\" not known".PHP_EOL.PHP_EOL;
                $output .= $this->printUsage();
                throw new CLIException($output, 3);
        } //end switch
        return $pos;
    }

    private function processUnknownArgument($arg)
    {
        $this->files = array_merge($this->files, $this->scanpath($arg));
    }

    private function printUsage()
    {
        //  $this->climate->output->addDefault('buffer');
        $this->climate->to('buffer')->usage();
        $str = $this->climate->output->get('buffer')->get();
        return $str;
    }
}