Issues (20)

Branch: master

src/Step/Data/Load.php (1 issue)

Labels
Severity
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\Data;
15
16
use Cecil\Collection\Page\PrefixSuffix;
17
use Cecil\Step\AbstractStep;
18
use Cecil\Util;
19
use Symfony\Component\Finder\Finder;
20
use Symfony\Component\Serializer\Encoder\CsvEncoder;
21
use Symfony\Component\Serializer\Encoder\JsonEncoder;
22
use Symfony\Component\Serializer\Encoder\XmlEncoder;
23
use Symfony\Component\Serializer\Encoder\YamlEncoder;
24
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
25
use Symfony\Component\Serializer\Serializer;
26
27
/**
28
 * Load step class.
29
 *
30
 * This class is responsible for loading data files from a specified directory,
31
 * decoding their contents based on the file extension, and merging the data
32
 * into the builder's data collection. It supports various file formats such as
33
 * YAML, JSON, CSV, and XML. The loaded data is organized into a nested array
34
 * structure based on the file paths and language suffixes.
35
 */
36
class Load extends AbstractStep
37
{
38
    /**
39
     * {@inheritdoc}
40
     */
41 1
    public function getName(): string
42
    {
43 1
        return 'Loading data';
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 1
    public function init(array $options): void
50
    {
51 1
        if (is_dir($this->config->getDataPath()) && $this->config->isEnabled('data.load')) {
52 1
            $this->canProcess = true;
53
        }
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59 1
    public function process(): void
60
    {
61 1
        $files = Finder::create()
62 1
            ->files()
63 1
            ->in($this->config->getDataPath())
64 1
            ->name('/\.(' . implode('|', (array) $this->config->get('data.ext')) . ')$/')
65 1
            ->sortByName(true);
66
67 1
        if ($this->config->hasTheme()) {
68 1
            $themes = $this->config->getTheme();
69 1
            foreach ($themes ?? [] as $theme) {
70 1
                if (Util\File::getFS()->exists($this->config->getThemeDirPath($theme, 'data'))) {
71
                    $files->in($this->config->getThemeDirPath($theme, 'data'));
72
                }
73
            }
74
        }
75
76 1
        $total = \count($files);
77
78 1
        if ($total < 1) {
79
            $message = 'No files';
80
            $this->builder->getLogger()->info($message);
81
82
            return;
83
        }
84
85 1
        $serializerYaml = new Serializer([new ObjectNormalizer()], [new YamlEncoder()]);
86 1
        $serializerJson = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
87 1
        $serializerCsv = new Serializer([new ObjectNormalizer()], [new CsvEncoder()]);
88 1
        $serializerXml = new Serializer([new ObjectNormalizer()], [new XmlEncoder()]);
89 1
        $count = 0;
90
91
        /** @var \Symfony\Component\Finder\SplFileInfo $file */
92 1
        foreach ($files as $file) {
93 1
            $count++;
94 1
            set_error_handler(
95 1
                function ($severity, $message, $file, $line) {
96
                    throw new \ErrorException($message, 0, $severity, $file, $line, null);
97 1
                }
98 1
            );
99 1
            $data = $file->getContents();
100 1
            restore_error_handler();
101
102 1
            switch ($file->getExtension()) {
103 1
                case 'yml':
104 1
                case 'yaml':
105 1
                    $dataAsArray = $serializerYaml->decode($data, 'yaml');
106 1
                    break;
107 1
                case 'json':
108 1
                    $dataAsArray = $serializerJson->decode($data, 'json');
109 1
                    break;
110 1
                case 'csv':
111 1
                    $dataAsArray = $serializerCsv->decode($data, 'csv');
112 1
                    break;
113 1
                case 'xml':
114 1
                    $dataAsArray = $serializerXml->decode($data, 'xml');
115 1
                    break;
116
                default:
117
                    return;
118
            }
119
120 1
            $lang = $this->config->getLanguageDefault();
121 1
            if (PrefixSuffix::hasSuffix($file->getFilenameWithoutExtension())) {
122
                $lang = PrefixSuffix::getSuffix($file->getFilenameWithoutExtension());
123
            }
124 1
            $array = [];
125 1
            $path = Util::joinFile(pathinfo($file->getRelativePathname(), PATHINFO_DIRNAME), pathinfo($file->getRelativePathname(), PATHINFO_FILENAME));
0 ignored issues
show
It seems like pathinfo($file->getRelat...\Data\PATHINFO_DIRNAME) can also be of type array; however, parameter $path of Cecil\Util::joinFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

125
            $path = Util::joinFile(/** @scrutinizer ignore-type */ pathinfo($file->getRelativePathname(), PATHINFO_DIRNAME), pathinfo($file->getRelativePathname(), PATHINFO_FILENAME));
Loading history...
126 1
            $path = trim($path, './');
127 1
            $localizedPath = Util::joinFile((string) $lang, PrefixSuffix::sub($path));
128 1
            $this->pathToArray($array, $localizedPath, $dataAsArray);
129
130 1
            $dataAsArray = array_merge_recursive(
131 1
                $this->builder->getData(),
132 1
                $array
133 1
            );
134 1
            $this->builder->setData($dataAsArray);
135
136 1
            $message = \sprintf('File "%s" loaded', $file->getRelativePathname());
137 1
            $this->builder->getLogger()->info($message, ['progress' => [$count, $total]]);
138
        }
139
    }
140
141
    /**
142
     * Puts a path/value couple into an array.
143
     *
144
     * @param array  $arr       Target array
145
     * @param string $path      Source path
146
     * @param array  $value     Source values
147
     * @param string $separator Path separator (ie: '/')
148
     */
149 1
    private function pathToArray(array &$arr, string $path, array $value, string $separator = DIRECTORY_SEPARATOR): void
150
    {
151 1
        $keys = explode($separator, $path);
152 1
        foreach ($keys as $key) {
153 1
            $arr = &$arr[$key];
154
        }
155 1
        $arr = $value;
156
    }
157
}
158