Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
45.18% covered (danger)
45.18%
75 / 166
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Installer
45.18% covered (danger)
45.18%
75 / 166
0.00% covered (danger)
0.00%
0 / 6
289.57
0.00% covered (danger)
0.00%
0 / 1
 install
38.46% covered (danger)
38.46%
5 / 13
0.00% covered (danger)
0.00%
0 / 1
7.73
 installExternal
81.08% covered (warning)
81.08%
30 / 37
0.00% covered (danger)
0.00%
0 / 1
11.82
 createReference
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 createCollection
87.50% covered (warning)
87.50%
14 / 16
0.00% covered (danger)
0.00%
0 / 1
4.03
 createType
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
42
 uploadMedia
45.61% covered (danger)
45.61%
26 / 57
0.00% covered (danger)
0.00%
0 / 1
30.46
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   Modules\Media\Admin
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace Modules\Media\Admin;
16
17use Modules\Admin\Models\AccountMapper;
18use Modules\Admin\Models\NullAccount;
19use Modules\Media\Models\Collection;
20use Modules\Media\Models\CollectionMapper;
21use Modules\Media\Models\PathSettings;
22use phpOMS\Application\ApplicationAbstract;
23use phpOMS\Config\SettingsInterface;
24use phpOMS\Message\Http\HttpRequest;
25use phpOMS\Message\Http\HttpResponse;
26use phpOMS\Module\InstallerAbstract;
27use phpOMS\Module\ModuleInfo;
28use phpOMS\System\File\Local\Directory;
29use phpOMS\System\File\Local\File;
30use phpOMS\System\File\PathException;
31use phpOMS\Uri\HttpUri;
32
33/**
34 * Installer class.
35 *
36 * @package Modules\Media\Admin
37 * @license OMS License 2.0
38 * @link    https://jingga.app
39 * @since   1.0.0
40 */
41final class Installer extends InstallerAbstract
42{
43    /**
44     * Path of the file
45     *
46     * @var string
47     * @since 1.0.0
48     */
49    public const PATH = __DIR__;
50
51    /**
52     * {@inheritdoc}
53     */
54    public static function install(ApplicationAbstract $app, ModuleInfo $info, SettingsInterface $cfgHandler) : void
55    {
56        if (!\is_dir(__DIR__ . '/../Files')) {
57            \mkdir(__DIR__ . '/../Files');
58        }
59
60        if (!\is_dir(__DIR__ . '/../../../temp')) {
61            \mkdir(__DIR__ . '/../../../temp');
62        }
63
64        parent::install($app, $info, $cfgHandler);
65
66        // Create directory for admin account
67        // All other accounts are automatically created in the admin module whenever they get created
68        // However, the admin account is created before the Media module is installed
69        // Because of this, the directory needs to be created manually after the Media installation
70        // The admin account should be the only DB account, but we use a loop of all accounts to avoid bugs
71        /** @var \Modules\Admin\Models\Account[] $accounts */
72        $accounts = AccountMapper::getAll()->execute();
73
74        foreach ($accounts as $account) {
75            $collection       = new Collection();
76            $collection->name = ((string) $account->id) . ' ' . $account->login;
77            $collection->setVirtualPath('/Accounts');
78            $collection->setPath('/Modules/Media/Files/Accounts/' . ((string) $account->id));
79            // The installation is always run by the admin account since the module is a "base" module which is always installed during the application setup
80            $collection->createdBy = new NullAccount(1);
81
82            CollectionMapper::create()->execute($collection);
83        }
84    }
85
86    /**
87     * Install data from providing modules.
88     *
89     * The data can be either directories which should be created or files which should be "uploaded"
90     *
91     * @param ApplicationAbstract $app  Application
92     * @param array               $data Additional data
93     *
94     * @return array
95     *
96     * @throws PathException
97     * @throws \Exception
98     *
99     * @since 1.0.0
100     */
101    public static function installExternal(ApplicationAbstract $app, array $data) : array
102    {
103        if (!\is_file($data['path'] ?? '')) {
104            throw new PathException($data['path'] ?? '');
105        }
106
107        $mediaFile = \file_get_contents($data['path'] ?? '');
108        if ($mediaFile === false) {
109            throw new PathException($data['path'] ?? ''); // @codeCoverageIgnore
110        }
111
112        $mediaData = \json_decode($mediaFile, true) ?? [];
113        if ($mediaData === false) {
114            throw new \Exception(); // @codeCoverageIgnore
115        }
116
117        $apiApp = new class() extends ApplicationAbstract
118        {
119            protected string $appName = 'Api';
120        };
121
122        $apiApp->dbPool         = $app->dbPool;
123        $apiApp->unitId         = $app->unitId;
124        $apiApp->accountManager = $app->accountManager;
125        $apiApp->appSettings    = $app->appSettings;
126        $apiApp->moduleManager  = $app->moduleManager;
127        $apiApp->eventManager   = $app->eventManager;
128
129        $result = [
130            'collection' => [],
131            'upload'     => [],
132            'type'       => [],
133        ];
134
135        if (!\is_dir(__DIR__ . '/../../../temp')) {
136            \mkdir(__DIR__ . '/../../../temp');
137        }
138
139        /** @var array<string, array> $mediaData */
140        foreach ($mediaData as $media) {
141            switch ($media['type']) {
142                case 'collection':
143                    $result['collection'][] = self::createCollection($apiApp, $media);
144                    break;
145                case 'upload':
146                    $result['upload'][] = self::uploadMedia($apiApp, $media);
147                    break;
148                case 'type':
149                    $result['type'][] = self::createType($apiApp, $media);
150                    break;
151                case 'reference':
152                    $result['reference'][] = self::createReference($apiApp, $media);
153                    break;
154                default:
155            }
156        }
157
158        return $result;
159    }
160
161    /**
162     * Create collection.
163     *
164     * @param ApplicationAbstract                                                            $app  Application
165     * @param array{path?:string, name?:string, virtualPath?:string, create_directory?:bool} $data Media info
166     *
167     * @return array
168     *
169     * @since 1.0.0
170     */
171    private static function createReference(ApplicationAbstract $app, array $data) : array
172    {
173        /** @var \Modules\Media\Controller\ApiController $module */
174        $module = $app->moduleManager->getModuleInstance('Media');
175
176        $response = new HttpResponse();
177        $request  = new HttpRequest(new HttpUri(''));
178
179        $request->header->account = 1;
180        $request->setData('name', $data['name'] ?? '');
181        $request->setData('virtualpath', $data['from'] ?? '/');
182        $request->setData('child', $data['to'] ?? '/');
183
184        $module->apiReferenceCreate($request, $response);
185
186        $responseData = $response->get('');
187        if (!\is_array($responseData)) {
188            return [];
189        }
190
191        return \is_array($responseData['response'])
192            ? $responseData['response']
193            : $responseData['response']->toArray();
194    }
195
196    /**
197     * Create collection.
198     *
199     * @param ApplicationAbstract                                                            $app  Application
200     * @param array{path?:string, name?:string, virtualPath?:string, create_directory?:bool} $data Media info
201     *
202     * @return array
203     *
204     * @since 1.0.0
205     */
206    private static function createCollection(ApplicationAbstract $app, array $data) : array
207    {
208        /** @var \Modules\Media\Controller\ApiController $module */
209        $module = $app->moduleManager->getModuleInstance('Media');
210
211        $path = isset($data['path']) ? ($data['path']) : $data['virtualPath'] ?? '';
212
213        $response = new HttpResponse();
214        $request  = new HttpRequest(new HttpUri(''));
215
216        $request->header->account = 1;
217        $request->setData('name', $data['name'] ?? '');
218        $request->setData('virtualpath', $data['virtualPath'] ?? '/');
219        $request->setData('path', $path);
220        $request->setData('create_directory', $data['create_directory'] ?? false);
221
222        $module->apiCollectionCreate($request, $response);
223
224        $responseData = $response->get('');
225        if (!\is_array($responseData)) {
226            return [];
227        }
228
229        return \is_array($responseData['response'])
230            ? $responseData['response']
231            : $responseData['response']->toArray();
232    }
233
234    /**
235     * Create type.
236     *
237     * @param ApplicationAbstract $app  Application
238     * @param array               $data Media info
239     *
240     * @return array
241     *
242     * @since 1.0.0
243     */
244    private static function createType(ApplicationAbstract $app, array $data) : array
245    {
246        /** @var \Modules\Media\Controller\ApiController $module */
247        $module = $app->moduleManager->get('Media');
248
249        $response = new HttpResponse();
250        $request  = new HttpRequest(new HttpUri(''));
251
252        $request->header->account = 1;
253        $request->setData('name', $data['name'] ?? '');
254
255        if (!empty($data['l11n'])) {
256            $request->setData('title', \reset($data['l11n'])['title']);
257            $request->setData('lang', \reset($data['l11n'])['lang']);
258        }
259
260        $module->apiMediaTypeCreate($request, $response);
261
262        $responseData = $response->get('');
263        if (!\is_array($responseData)) {
264            return [];
265        }
266
267        $type = $responseData['response'];
268        $id   = $type->id;
269
270        $isFirst = true;
271        foreach ($data['l11n'] as $l11n) {
272            if ($isFirst) {
273                $isFirst = false;
274                continue;
275            }
276
277            $response = new HttpResponse();
278            $request  = new HttpRequest(new HttpUri(''));
279
280            $request->header->account = 1;
281            $request->setData('title', $l11n['title'] ?? '');
282            $request->setData('lang', $l11n['lang'] ?? null);
283            $request->setData('type', $id);
284
285            $module->apiMediaTypeL11nCreate($request, $response);
286        }
287
288        return \is_array($type)
289            ? $type
290            : $type->toArray();
291    }
292
293    /**
294     * Upload media.
295     *
296     * @param ApplicationAbstract $app  Application
297     * @param array               $data Media info
298     *
299     * @return array
300     *
301     * @since 1.0.0
302     */
303    private static function uploadMedia(ApplicationAbstract $app, array $data) : array
304    {
305        /** @var \Modules\Media\Controller\ApiController $module */
306        $module = $app->moduleManager->get('Media');
307
308        $response = new HttpResponse();
309        $request  = new HttpRequest(new HttpUri(''));
310
311        $request->header->account = 1;
312        $request->setData('path', empty($data['path'] ?? '') ? '' : $data['path']);
313        $request->setData('virtualPath',
314            (string) (
315                $data['create_collection']
316                    ? \rtrim($data['virtualPath'] ?? '/', '/') . '/' . ((string) ($data['name'] ?? ''))
317                    : ($data['virtualPath'] ?? '/')
318            )
319        );
320        $request->setData('type', $data['media_type'] ?? null); // = identifier for modules
321        $request->setData('pathsettings', $data['path_setting'] ?? PathSettings::FILE_PATH);
322
323        $tempPath = __DIR__ . '/../../../temp/';
324
325        foreach ($data['files'] as $file) {
326            $filePath = __DIR__ . '/../../..' . $file;
327
328            if (\is_file($filePath)) {
329                File::copy($filePath, $tempPath . $file, true);
330
331                $request->addFile([
332                    'size'     => \filesize($tempPath . $file),
333                    'name'     => \basename($file),
334                    'tmp_name' => $tempPath . $file,
335                    'error'    => \UPLOAD_ERR_OK,
336                ]);
337            } if (\is_dir($filePath)) {
338                Directory::copy($filePath, $tempPath . \basename($filePath), true);
339
340                $iterator = new \RecursiveIteratorIterator(
341                    new \RecursiveDirectoryIterator($tempPath . \basename($filePath), \RecursiveDirectoryIterator::SKIP_DOTS),
342                    \RecursiveIteratorIterator::SELF_FIRST
343                );
344
345                /** @var \DirectoryIterator $iterator */
346                foreach ($iterator as $item) {
347                    if ($item->isDir()) {
348                        continue;
349                    }
350
351                    $request->addFile([
352                        'size'     => \filesize($item->getPathname()),
353                        'name'     => \basename($item->getPathname()),
354                        'tmp_name' => $item->getPathname(),
355                        'error'    => \UPLOAD_ERR_OK,
356                    ]);
357                }
358            }
359        }
360
361        $module->apiMediaUpload($request, $response);
362
363        $uploadedIds = $response->getDataArray('')['response'];
364
365        if ($data['create_collection'] ?? false) {
366            $response = new HttpResponse();
367            $request  = new HttpRequest(new HttpUri(''));
368
369            $request->header->account = 1;
370            $request->setData('name', (string) ($data['name'] ?? ''));
371            $request->setData('virtualpath', (string) ($data['virtualPath'] ?? '/'));
372            $request->setData('path', (string) ($data['path'] ?? '/Modules/Media/Files/' . ((string) ($data['name'] ?? ''))));
373            $request->setData('media-list', \json_encode($uploadedIds));
374
375            $module->apiCollectionCreate($request, $response);
376        }
377
378        $responseData = $response->get('');
379        if (!\is_array($responseData)) {
380            return [];
381        }
382
383        return \is_array($responseData['response'])
384            ? $responseData['response']
385            : $responseData['response']->toArray();
386    }
387}