Completed
Push — develop ( 8fda15...dbbcf5 )
by Jaap
14s
created

Scrybe/Command/Manual/BaseConvertCommand.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Plugin\Scrybe\Command\Manual;
13
14
use phpDocumentor\Command\Command;
15
use phpDocumentor\Fileset\Collection;
16
use phpDocumentor\Plugin\Scrybe\Converter\ConverterInterface;
17
use phpDocumentor\Plugin\Scrybe\Converter\Factory as ConverterFactory;
18
use phpDocumentor\Plugin\Scrybe\Converter\Format;
19
use phpDocumentor\Plugin\Scrybe\Template\Factory;
20
use phpDocumentor\Plugin\Scrybe\Template\TemplateInterface;
21
use Symfony\Component\Console\Input\InputArgument;
22
use Symfony\Component\Console\Input\InputInterface;
23
use Symfony\Component\Console\Input\InputOption;
24
use Symfony\Component\Console\Output\OutputInterface;
25
26
/**
27
 * Abstract Command class containing the scaffolding for the subsequent converting commands.
28
 */
29
abstract class BaseConvertCommand extends Command
30
{
31
    /** @var ConverterFactory */
32
    protected $converterFactory;
33
34
    /** @var Factory */
35
    protected $templateFactory;
36
37
    /** @var string The string representation of the output format */
38
    protected $output_format = Format\Format::HTML;
39
40
    /**
41
     * Initializes this command with a template and converter factory.
42
     *
43
     * @param string $name
44
     */
45
    public function __construct($name, Factory $templateFactory, ConverterFactory $converterFactory)
46
    {
47
        parent::__construct($name);
48
49
        $this->templateFactory = $templateFactory;
50
        $this->converterFactory = $converterFactory;
51
    }
52
53
    /**
54
     * Configures the options and default help text.
55
     */
56
    protected function configure()
57
    {
58
        $this
59
            ->addOption(
60
                'target',
61
                't',
62
                InputOption::VALUE_OPTIONAL,
63
                'target location for output',
64
                'build'
65
            )
66
            ->addOption(
67
                'input-format',
68
                'i',
69
                InputOption::VALUE_OPTIONAL,
70
                'which input format does the documentation sources have?',
71
                'rst'
72
            )
73
            ->addOption(
74
                'title',
75
                null,
76
                InputOption::VALUE_OPTIONAL,
77
                'The title of this document',
78
                'Scrybe'
79
            )
80
            ->addOption(
81
                'template',
82
                null,
83
                InputOption::VALUE_OPTIONAL,
84
                'which template should be used to generate the documentation?',
85
                'default'
86
            )
87
            ->addArgument(
88
                'source',
89
                InputArgument::IS_ARRAY | InputArgument::REQUIRED,
90
                'One or more files or directories to fetch files from'
91
            );
92
93
        $this->setHelp(
94
            <<<DESCRIPTION
95
Generates reference documentation as {$this->output_format}.
96
97
You can define the type of files use as input using the <info>--input-format</info>
98
of <info>-i</info> option.
99
100
DESCRIPTION
101
        );
102
    }
103
104
    /**
105
     * Execute the transformation process to an output format as defined in the
106
     * $output_format class variable.
107
     *
108
     * @see BaseConvertCommand::$output_format to determine the output format.
109
     * @return int
110
     */
111
    protected function execute(InputInterface $input, OutputInterface $output)
112
    {
113
        $this->getHelper('phpdocumentor_logger')->connectOutputToLogging($output, $this);
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method connectOutputToLogging() does only exist in the following implementations of said interface: phpDocumentor\Command\Helper\LoggerHelper.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
114
115
        $converter = $this->getConverter($input);
116
        $converter->setOption('title', $input->getOption('title'));
117
118
        $output->writeln('Collect all documents');
119
        $files = $this->buildCollection(
120
            $input->getArgument('source'),
121
            $converter->getDefinition()->getInputFormat()->getExtensions()
122
        );
123
124
        $output->writeln('Converting documents');
125
        $files = $converter->convert($files, $this->getTemplate($input));
126
127
        $output->writeln('Writing converted documents to disk');
128
        $this->writeToDisk($files, $input->getOption('target'));
129
130
        $output->writeln('Writing assets to disk');
131
        $converter->getAssets()->copyTo($input->getOption('target'));
132
    }
133
134
    /**
135
     * @param string[] $files
136
     * @param string $destination
137
     */
138
    protected function writeToDisk($files, $destination)
139
    {
140
        foreach ($files as $relative_path => $contents) {
141
            $full_path = $destination . '/' . $relative_path;
142
143
            $destination_folder = dirname($full_path);
144
            if (!file_exists($destination_folder)) {
145
                mkdir($destination_folder, 0777, true);
146
            }
147
148
            file_put_contents($full_path, $contents);
149
        }
150
    }
151
152
    /**
153
     * Returns a template object based off the human-readable template name.
154
     *
155
     * @return TemplateInterface
156
     */
157
    protected function getTemplate(InputInterface $input)
158
    {
159
        $template = $this->getTemplateFactory()->get('twig');
160
        $template->setName($input->getOption('template'));
161
162
        return $template;
163
    }
164
165
    /**
166
     * Returns the converter for this operation.
167
     *
168
     * @return ConverterInterface
169
     */
170
    protected function getConverter(InputInterface $input)
171
    {
172
        return $this->getConverterFactory()->get($input->getOption('input-format'), $this->output_format);
173
    }
174
175
    /**
176
     * Constructs a Fileset collection and returns that.
177
     *
178
     * @param array $sources    List of source paths.
179
     * @param array $extensions List of extensions to scan for in directories.
180
     *
181
     * @return Collection
182
     */
183
    protected function buildCollection(array $sources, array $extensions)
184
    {
185
        $collection = new Collection();
186
        $collection->setAllowedExtensions($extensions);
187
        foreach ($sources as $path) {
188
            if (is_dir($path)) {
189
                $collection->addDirectory($path);
190
                continue;
191
            }
192
193
            $collection->addFile($path);
194
        }
195
196
        return $collection;
197
    }
198
199
    /**
200
     * Returns a factory object that can return any Scrybe template.
201
     *
202
     * @return Factory
203
     */
204
    protected function getTemplateFactory()
205
    {
206
        return $this->templateFactory;
207
    }
208
209
    /**
210
     * Returns the factory for converters.
211
     *
212
     * @return ConverterFactory
213
     */
214
    public function getConverterFactory()
215
    {
216
        return $this->converterFactory;
217
    }
218
}
219