Passed
Push — master ( db2b61...d91102 )
by Dan
03:24
created

CommandsHelper::insertWords()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 4
1
<?php
2
3
namespace SixtyNine\Cloud\Command;
4
5
use Imagine\Image\ImageInterface;
6
use SixtyNine\Cloud\Builder\CloudBuilder;
7
use SixtyNine\Cloud\Builder\FiltersBuilder;
8
use SixtyNine\Cloud\Builder\PalettesBuilder;
9
use SixtyNine\Cloud\Builder\WordsListBuilder;
10
use SixtyNine\Cloud\Color\ColorGeneratorInterface;
11
use SixtyNine\Cloud\Color\RandomColorGenerator;
12
use SixtyNine\Cloud\Color\RotateColorGenerator;
13
use SixtyNine\Cloud\Factory\FontsFactory;
14
use SixtyNine\Cloud\Factory\PlacerFactory;
15
use SixtyNine\Cloud\FontSize\BoostFontSizeGenerator;
16
use SixtyNine\Cloud\FontSize\DimFontSizeGenerator;
17
use SixtyNine\Cloud\FontSize\FontSizeGeneratorInterface;
18
use SixtyNine\Cloud\FontSize\LinearFontSizeGenerator;
19
use SixtyNine\Cloud\Placer\PlacerInterface;
20
use SixtyNine\Cloud\Renderer\CloudRenderer;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Webmozart\Assert\Assert;
23
24
class CommandsHelper
25
{
26
    protected $fontSizeBoosts = array('linear', 'dim', 'boost');
27
    protected $paletteTypes = array('cycle', 'random');
28
    protected $outputFormats = array('gif', 'jpeg', 'png');
29
30
    /**
31
     * @param string $name
32
     * @return PlacerInterface
33
     * @throws \InvalidArgumentException
34
     */
35
    public function getPlacer($name)
36
    {
37
        $availablePlacers = PlacerFactory::getInstance()->getPlacersNames();
38
39
        if ($name) {
40
            Assert::oneOf($name, $availablePlacers, 'Word placer not found: ' . $name);
41
            return $name;
42
        }
43
44
        Assert::notEmpty($availablePlacers, 'No word placers available');
45
        return $availablePlacers[0];
46
    }
47
48
    /**
49
     * @param FontsFactory $factory
50
     * @param string $font
51
     * @return string
52
     * @throws \InvalidArgumentException
53
     */
54
    public function getFont(FontsFactory $factory, $font)
55
    {
56
        if ($font) {
57
            return $font;
58
        }
59
60
        Assert::notEmpty($factory->getFonts(), 'No font file found');
61
        return $factory->getFonts()[0];
62
    }
63
64
    /**
65
     * @param string $type
66
     * @return FontSizeGeneratorInterface
67
     * @throws \InvalidArgumentException
68
     */
69
    public function getFontSizeGenerator($type = 'linear')
70
    {
71
        Assert::oneOf($type, $this->fontSizeBoosts, 'Invalid font size boost: ' . $type);
72
73
        $generatorClass = LinearFontSizeGenerator::class;
74
        if ($type === 'dim') {
75
            $generatorClass = DimFontSizeGenerator::class;
76
        }
77
        if ($type === 'boost') {
78
            $generatorClass = BoostFontSizeGenerator::class;
79
        }
80
81
        return new $generatorClass();
82
    }
83
84
    /**
85
     * @param string $paletteName
86
     * @param string $paletteType
87
     * @param string $palettesFile
88
     * @return bool|ColorGeneratorInterface
89
     * @throws \InvalidArgumentException
90
     */
91
    public function getColorGenerator($paletteName, $paletteType, $palettesFile = null)
92
    {
93
        if ($paletteName && $paletteType) {
94
95
            Assert::oneOf($paletteType, $this->paletteTypes, 'Palette type must be either "cycle" or "random"');
96
97
            $file = $palettesFile
98
                ? $palettesFile
99
                : __DIR__ . '/../Resources/palettes.yml'
100
            ;
101
            $paletteBuilder = PalettesBuilder::create()->importPalettes($file);
102
103
            $palette = $paletteBuilder->getNamedPalette($paletteName);
104
            $generatorClass = ($paletteType === 'cycle')
105
                ? RotateColorGenerator::class
106
                : RandomColorGenerator::class
107
            ;
108
            return new $generatorClass($palette);
109
        }
110
111
        return false;
112
    }
113
114
    /**
115
     * @param ImageInterface $image
116
     * @param string $outputFormat
117
     * @param string $outputFile
118
     * @throws \InvalidArgumentException
119
     */
120
    public function output(ImageInterface $image, $outputFormat, $outputFile = null)
121
    {
122
        Assert::oneOf($outputFormat, $this->outputFormats, 'Invalid output format: ' . $outputFormat);
123
124
        if ($outputFile) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $outputFile of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
125
            $image->save($outputFile, array('format' => $outputFormat));
126
            return;
127
        }
128
129
        echo $image->get($outputFormat);
130
    }
131
132
    /**
133
     * @param CloudBuilder $cloudBuilder
134
     * @param FontsFactory $factory
135
     * @param PlacerInterface $placer
136
     * @param bool $renderBoxes
137
     * @return \Imagine\Gd\Image|ImageInterface
138
     */
139
    protected function render(CloudBuilder $cloudBuilder, FontsFactory $factory, PlacerInterface $placer = null, $renderBoxes = false)
140
    {
141
        $renderer = new CloudRenderer();
142
        $image = $renderer->render($cloudBuilder->build(), $factory, $renderBoxes);
143
144
        if ($placer) {
145
            $renderer->renderUsher($image, $placer, '#FF0000');
146
        }
147
148
        return $image;
149
    }
150
151
    /**
152
     * @param int $minWordLength
153
     * @param int $maxWordLength
154
     * @param null $changeCase
155
     * @param bool $noRemoveNumbers
156
     * @param bool $noRemoveUnwanted
157
     * @param bool $noRemoveTrailing
158
     * @return FiltersBuilder
159
     */
160
    public function getFilterBuilder(
161
        $minWordLength,
162
        $maxWordLength,
163
        $changeCase = null,
164
        $noRemoveNumbers = false,
165
        $noRemoveUnwanted = false,
166
        $noRemoveTrailing = false
167
    ) {
168
        $filtersBuilder = FiltersBuilder::create()
169
            ->setMinLength($minWordLength)
170
            ->setMaxLength($maxWordLength)
171
            ->setRemoveNumbers(!$noRemoveNumbers)
172
            ->setRemoveUnwanted(!$noRemoveTrailing)
173
            ->setRemoveTrailing(!$noRemoveUnwanted)
174
        ;
175
176
        if ($changeCase && in_array($changeCase, $filtersBuilder->getAllowedCase())) {
177
            $filtersBuilder->setCase($changeCase);
178
        }
179
180
        return $filtersBuilder;
181
    }
182
183
    /**
184
     * @param WordsListBuilder $builder
185
     * @param string $type
186
     * @param string $file
187
     * @param string $url
188
     */
189
    public function insertWords(WordsListBuilder $builder, $type, $file = null, $url = null)
190
    {
191
        Assert::true(null !== $file | null !== $url);
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: (null !== $file) | null !== $url, Probably Intended Meaning: null !== ($file | null !== $url)

When comparing the result of a bit operation, we suggest to add explicit parenthesis and not to rely on PHP’s built-in operator precedence to ensure the code behaves as intended and to make it more readable.

Let’s take a look at these examples:

// Returns always int(0).
return 0 === $foo & 4;
return (0 === $foo) & 4;

// More likely intended return: true/false
return 0 === ($foo & 4);
Loading history...
192
        Assert::oneOf($type, array('from-url', 'from-file'), 'Invalid type for createCloud: ' . $type);
193
194
        if ($type === 'from-file') {
195
            Assert::fileExists($file, 'File not found: ' . $file);
196
            $builder->importWords(file_get_contents($file));
197
        } else {
198
            $builder->importUrl($url);
199
        }
200
201
    }
202
203
    /**
204
     * @param WordsListBuilder $builder
205
     * @param string $sortBy
206
     * @param string $sortOrder
207
     */
208
    public function sortWords(WordsListBuilder $builder, $sortBy, $sortOrder)
209
    {
210
        if ($sortBy && $sortOrder) {
211
            $builder->sort($sortBy, $sortOrder);
212
        }
213
    }
214
215
    /**
216
     * @param string $type
217
     * @param InputInterface $input
218
     * @throws \InvalidArgumentException
219
     */
220
    public function createCloud($type, InputInterface $input)
221
    {
222
        Assert::oneOf($type, array('from-url', 'from-file'), 'Invalid type for createCloud: ' . $type);
223
224
        // Build the filters
225
        $filtersBuilder = $this->getFilterBuilder(
226
            $input->getOption('min-word-length'),
227
            $input->getOption('max-word-length'),
228
            $input->getOption('case'),
229
            $input->getOption('no-remove-numbers'),
230
            $input->getOption('no-remove-unwanted'),
231
            $input->getOption('no-remove-trailing')
232
        );
233
234
        // Create a placer
235
        $placerName = $this->getPlacer($input->getOption('placer'));
236
        $placer = PlacerFactory::getInstance()->getPlacer(
237
            $placerName,
238
            $input->getOption('width'),
239
            $input->getOption('height')
240
        );
241
242
        // Get the font file
243
        $fontsPath = $input->getOption('fonts-path')
244
            ? realpath($input->getOption('fonts-path'))
245
            : constant('BASE_PATH') . '/fonts'
246
        ;
247
        $factory = FontsFactory::create($fontsPath);
248
        $font = $this->getFont($factory, $input->getOption('font'));
249
250
        // Create the list builder
251
        $listBuilder = WordsListBuilder::create()
252
            ->setMaxWords($input->getOption('max-word-count'))
253
            ->setFilters($filtersBuilder->build())
254
            ->randomizeOrientation($input->getOption('vertical-probability'))
255
        ;
256
257
        $this->insertWords($listBuilder, $type, $input->getArgument('file'), $input->getArgument('url'));
258
259
        $this->sortWords($listBuilder, $input->getOption('sort-by'), $input->getOption('sort-order'));
260
261
        // Apply a color generator if needed
262
        $colorGenerator = $this->getColorGenerator(
263
            $input->getOption('palette'),
264
            $input->getOption('palette-type'),
265
            $input->getOption('palettes-file')
266
        );
267
268
        if ($colorGenerator) {
269
            $listBuilder->randomizeColors($colorGenerator);
270
        }
271
272
        // Build the list
273
        $list = $listBuilder->build('list');
274
275
        // Create a cloud builder
276
        $cloudBuilder = CloudBuilder::create($factory)
277
            ->setBackgroundColor($input->getOption('background-color'))
278
            ->setDimension($input->getOption('width'), $input->getOption('height'))
279
            ->setFont($font)
280
            ->setFontSizes($input->getOption('min-font-size'), $input->getOption('max-font-size'))
281
            ->setPlacer($placerName)
282
            ->setSizeGenerator($this->getFontSizeGenerator($input->getOption('font-size-boost')))
283
            ->useList($list)
284
        ;
285
286
        if ($input->getOption('preLoggercise')) {
287
            $cloudBuilder->setPrecise();
288
        }
289
290
        // Render the cloud and show the bounding boxes and the usher if needed
291
        $image = $this->render(
292
            $cloudBuilder,
293
            $factory,
294
            $input->getOption('render-usher') ? $placer : null,
295
            $input->getOption('render-boxes')
296
        );
297
298
        $this->output($image, $input->getOption('format'), $input->getOption('save-to-file'));
299
    }
300
}
301