Completed
Push — 4-cactus ( f0b320...c9f1dc )
by Alberto
19s queued 16s
created

UploadableBehavior::copyFiles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2017-2021 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\Core\Model\Behavior;
15
16
use BEdita\Core\Filesystem\FilesystemRegistry;
17
use Cake\Event\Event;
18
use Cake\ORM\Behavior;
19
use Cake\ORM\Entity;
20
use League\Flysystem\MountManager;
21
use Psr\Http\Message\StreamInterface;
22
23
/**
24
 * Upload files.
25
 *
26
 * @since 4.0.0
27
 */
28
class UploadableBehavior extends Behavior
29
{
30
    /**
31
     * @inheritDoc
32
     */
33
    protected $_defaultConfig = [
34
        'files' => [
35
            [
36
                'path' => 'path',
37
                'contents' => 'contents',
38
            ],
39
        ],
40
        'implementedMethods' => [
41
            'copyFiles' => 'copyFiles',
42
        ],
43
    ];
44
45
    /**
46
     * Write file contents.
47
     *
48
     * @param \League\Flysystem\MountManager $manager Mount manager.
49
     * @param string $path File path.
50
     * @param mixed $contents File contents.
51
     * @return bool
52
     */
53
    protected function write(MountManager $manager, $path, $contents)
54
    {
55
        if ($contents instanceof StreamInterface) {
56
            $contents = $contents->detach();
57
        }
58
59
        if (is_resource($contents)) {
60
            return $manager->putStream($path, $contents);
61
        }
62
63
        return $manager->put($path, $contents);
64
    }
65
66
    /**
67
     * Process upload of a single file.
68
     *
69
     * @param \Cake\ORM\Entity $entity Entity.
70
     * @param string $pathField Name of field in which path is stored.
71
     * @param string $contentsField Name of field in which contents are stored.
72
     * @return bool
73
     */
74
    protected function processUpload(Entity $entity, $pathField, $contentsField)
75
    {
76
        $manager = FilesystemRegistry::getMountManager();
77
        if (
78
            (!$entity->isDirty($pathField) || !$manager->has($entity->getOriginal($pathField)))
79
            && !$entity->isDirty($contentsField)
80
        ) {
81
            // Nothing to do.
82
            return true;
83
        }
84
85
        $path = $entity->get($pathField);
86
        $originalPath = $entity->getOriginal($pathField);
87
        if ($entity->isDirty($pathField) && $originalPath !== $path) {
88
            if ($entity->isDirty($contentsField)) {
89
                // Delete and re-upload.
90
                return $manager->delete($originalPath) && $this->write($manager, $path, $entity->get($contentsField));
91
            }
92
93
            // Move to new location.
94
            return $manager->move($originalPath, $path);
95
        }
96
97
        // Updated contents.
98
        return $this->write($manager, $path, $entity->get($contentsField));
99
    }
100
101
    /**
102
     * Set `private` file visibility on `private_url`
103
     *
104
     * @param \Cake\ORM\Entity $entity Entity.
105
     * @param string $pathField Name of field in which path is stored.
106
     * @return void
107
     */
108
    protected function setVisibility(Entity $entity, $pathField): void
109
    {
110
        if (!$entity->get('private_url')) {
111
            return;
112
        }
113
        $path = $entity->get($pathField);
114
        $manager = FilesystemRegistry::getMountManager();
115
        $manager->setVisibility($path, 'private');
116
    }
117
118
    /**
119
     * Process delete of a single file.
120
     *
121
     * @param \Cake\ORM\Entity $entity Entity.
122
     * @param string $pathField Name of field in which path is stored.
123
     * @return bool
124
     */
125
    protected function processDelete(Entity $entity, $pathField)
126
    {
127
        $manager = FilesystemRegistry::getMountManager();
128
        $path = $entity->get($pathField);
129
130
        return !$manager->has($path) || $manager->delete($path);
131
    }
132
133
    /**
134
     * Process upload.
135
     *
136
     * @param \Cake\Event\Event $event Dispatched event.
137
     * @param \Cake\ORM\Entity $entity Entity.
138
     * @return void
139
     */
140
    public function afterSave(Event $event, Entity $entity)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

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

140
    public function afterSave(/** @scrutinizer ignore-unused */ Event $event, Entity $entity)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
141
    {
142
        foreach ($this->getConfig('files') as $file) {
143
            $this->processUpload($entity, $file['path'], $file['contents']);
144
            $this->setVisibility($entity, $file['path']);
145
        }
146
    }
147
148
    /**
149
     * Process delete.
150
     *
151
     * @param \Cake\Event\Event $event Dispatched event.
152
     * @param \Cake\ORM\Entity $entity Entity.
153
     * @return void
154
     */
155
    public function afterDelete(Event $event, Entity $entity)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

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

155
    public function afterDelete(/** @scrutinizer ignore-unused */ Event $event, Entity $entity)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
    {
157
        foreach ($this->getConfig('files') as $file) {
158
            $this->processDelete($entity, $file['path']);
159
        }
160
    }
161
162
    /**
163
     * Copy files from an entity to another.
164
     *
165
     * @param \Cake\ORM\Entity $src Source entity. It must have path fields set and referenced files must exist.
166
     * @param \Cake\ORM\Entity $dest Destination entity. It must have path fields set.
167
     * @return void
168
     * @throws \League\Flysystem\FilesystemException
169
     */
170
    public function copyFiles(Entity $src, Entity $dest): void
171
    {
172
        $manager = FilesystemRegistry::getMountManager();
173
        foreach ($this->getConfig('files') as $file) {
174
            $srcPath = $src->get($file['path']);
175
            $destPath = $dest->get($file['path']);
176
177
            $manager->copy($srcPath, $destPath);
178
        }
179
    }
180
}
181