AbstractOptimize   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 111
rs 10
c 0
b 0
f 0
wmc 15

4 Methods

Rating   Name   Duplication   Size   Complexity  
B process() 0 55 9
A init() 0 10 4
A encode() 0 3 1
A decode() 0 3 1
1
<?php
2
3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Cecil\Step\Optimize;
15
16
use Cecil\Cache;
17
use Cecil\Exception\RuntimeException;
18
use Cecil\Step\AbstractStep;
19
use Cecil\Util;
20
use Symfony\Component\Finder\Finder;
21
22
/**
23
 * Abstract class for optimization steps.
24
 *
25
 * This class provides a base implementation for steps that optimize files
26
 * of a specific type (e.g., CSS, JS). It handles the initialization of the
27
 * optimization process, file processing, and caching of optimized files.
28
 */
29
abstract class AbstractOptimize extends AbstractStep
30
{
31
    /** @var string File type (ie: 'css') */
32
    protected $type;
33
34
    /** @var mixed File processor */
35
    protected $processor;
36
37
    /**
38
     * {@inheritdoc}
39
     */
40
    public function init(array $options): void
41
    {
42
        if ($options['dry-run']) {
43
            return;
44
        }
45
        if (!$this->config->isEnabled(\sprintf('optimize.%s', $this->type))) {
46
            return;
47
        }
48
        if ($this->config->isEnabled('optimize')) {
49
            $this->canProcess = true;
50
        }
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     *
56
     * @throws RuntimeException
57
     */
58
    public function process(): void
59
    {
60
        $this->setProcessor();
61
62
        $extensions = (array) $this->config->get(\sprintf('optimize.%s.ext', $this->type));
63
        if (empty($extensions)) {
64
            throw new RuntimeException(\sprintf('The config key "optimize.%s.ext" is empty.', $this->type));
65
        }
66
67
        $files = Finder::create()
68
            ->files()
69
            ->in($this->config->getOutputPath())
70
            ->name('/\.(' . implode('|', $extensions) . ')$/')
71
            ->notName('/\.min\.(' . implode('|', $extensions) . ')$/')
72
            ->sortByName(true);
73
        $max = \count($files);
74
75
        if ($max <= 0) {
76
            $this->builder->getLogger()->info('No files');
77
78
            return;
79
        }
80
81
        $count = 0;
82
        $optimized = 0;
83
        $cache = new Cache($this->builder, 'optimized');
84
85
        /** @var \Symfony\Component\Finder\SplFileInfo $file */
86
        foreach ($files as $file) {
87
            $count++;
88
            $sizeBefore = $file->getSize();
89
            $message = \sprintf('File "%s" processed', $this->builder->isDebug() ? $file->getPathname() : $file->getRelativePathname());
90
91
            $cacheKey = $cache->createKeyFromFile($file);
92
            if (!$cache->has($cacheKey)) {
93
                $processed = $this->processFile($file);
94
                $sizeAfter = \strlen($processed);
95
                if ($sizeAfter < $sizeBefore) {
96
                    $message = \sprintf(
97
                        'File "%s" optimized (%s Ko -> %s Ko)',
98
                        $this->builder->isDebug() ? $file->getPathname() : $file->getRelativePathname(),
99
                        ceil($sizeBefore / 1000),
100
                        ceil($sizeAfter / 1000)
101
                    );
102
                }
103
                $cache->set($cacheKey, $this->encode($processed));
104
                $optimized++;
105
106
                $this->builder->getLogger()->info($message, ['progress' => [$count, $max]]);
107
            }
108
            $processed = $this->decode($cache->get($cacheKey));
109
            Util\File::getFS()->dumpFile($file->getPathname(), $processed);
110
        }
111
        if ($optimized == 0) {
112
            $this->builder->getLogger()->info('Nothing to do');
113
        }
114
    }
115
116
    /**
117
     * Set file processor object.
118
     */
119
    abstract public function setProcessor(): void;
120
121
    /**
122
     * Process a file.
123
     */
124
    abstract public function processFile(\Symfony\Component\Finder\SplFileInfo $file): string;
125
126
    /**
127
     * Encode file content.
128
     */
129
    public function encode(?string $content = null): ?string
130
    {
131
        return $content;
132
    }
133
134
    /**
135
     * Decode file content.
136
     */
137
    public function decode(?string $content = null): ?string
138
    {
139
        return $content;
140
    }
141
}
142