MoveFiles::getDirContents()   A
last analyzed

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 15
rs 9.6111
1
<?php
2
3
namespace Sunnysideup\MoveLargeFilesToAssets;
4
5
use SilverStripe\Assets\File;
6
use SilverStripe\Assets\Folder;
7
use SilverStripe\Assets\Image;
8
use SilverStripe\Control\Controller;
9
use SilverStripe\Control\Director;
10
use SilverStripe\Dev\Tasks\MigrateFileTask;
11
use SilverStripe\ORM\DB;
12
13
class MoveFiles extends MigrateFileTask
14
{
15
    /**
16
     * {@inheritDoc}
17
     */
18
    protected $title = 'Copy (large / large number of) files to assets';
19
20
    /**
21
     * {@inheritDoc}
22
     */
23
    protected $description = 'Move predefined folder to assets/predefined folder and register in Database.';
24
25
    /**
26
     * {@inheritDoc}
27
     */
28
    protected $enabled = true;
29
30
    private static $segment = 'MoveFiles';
31
32
    private static $include_reset = true;
33
34
    private static $use_exec_for_copy = true;
35
36
    private static $folder_name = 'new-files';
37
38
    /**
39
     * {@inheritDoc}
40
     */
41
    public function run($request)
42
    {
43
        $folderNameFromConfig = self::config()->get('folder_name');
44
        $oldPathFromConfig = Controller::join_links(Director::baseFolder(), $folderNameFromConfig);
45
        $base = Director::baseFolder();
46
        $baseWithFolderNameFromConfig = Controller::join_links($base, $folderNameFromConfig);
0 ignored issues
show
Unused Code introduced by
The assignment to $baseWithFolderNameFromConfig is dead and can be removed.
Loading history...
47
48
        if (is_dir($oldPathFromConfig)) {
49
            $newPath = Controller::join_links(ASSETS_PATH, $folderNameFromConfig);
50
            $this->reset($newPath);
51
            $this->reset($newPath);
52
            DB::alteration_message('copying --' . $oldPathFromConfig . '-- to --' . $newPath);
53
            $this->rcopy($oldPathFromConfig, $newPath);
54
            $this->registerFiles($newPath);
55
            $this->defaultSubtasks = [
56
                'move-files',
57
                'migrate-folders',
58
                'generate-cms-thumbnails',
59
                'fix-folder-permissions',
60
                'fix-secureassets',
61
                'normalise-access',
62
            ];
63
            parent::run($request);
64
        }
65
    }
66
67
    public function reset($newPath)
68
    {
69
        if ($this->Config()->get('include_reset')) {
70
            $folderPath = str_replace(ASSETS_PATH . '/', '', $newPath);
71
            $folder = Folder::find_or_make($folderPath);
72
            if ($folder) {
0 ignored issues
show
introduced by
$folder is of type SilverStripe\Assets\Folder, thus it always evaluated to true.
Loading history...
73
                $folder->delete();
74
                DB::alteration_message('Deleting folder ' . $folderPath . ', based on ' . $newPath, 'deleted');
75
            }
76
            if (file_exists($newPath)) {
77
                $this->rrmdir($newPath);
78
                DB::alteration_message('Deleting folder ' . $folderPath . ', based on ' . $newPath . ', from file system', 'deleted');
79
            }
80
            if (file_exists($newPath)) {
81
                user_error('ERROR: Could not reset files', E_USER_ERROR);
82
            }
83
        } else {
84
            DB::alteration_message('OK: not including reset');
85
        }
86
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91
    protected function registerFiles($newPath)
92
    {
93
        $files = $this->getDirContents($newPath);
94
        foreach ($files as $newPath) {
0 ignored issues
show
introduced by
$newPath is overwriting one of the parameters of this function.
Loading history...
95
            $this->addToDb($newPath);
96
        }
97
    }
98
99
    protected function addToDb(string $newPath)
100
    {
101
        DB::alteration_message('considering ' . $newPath);
102
        if (! is_dir($newPath)) {
103
            $fileName = basename($newPath);
104
            $folderPath = str_replace(ASSETS_PATH . '/', '', dirname($newPath));
105
            $folder = Folder::find_or_make($folderPath);
106
            $filter = ['Name' => $fileName, 'ParentID' => $folder->ID];
107
            $file = File::get()->filter($filter)->exists();
108
            if (! $file) {
109
                if ($this->isImage($newPath)) {
110
                    DB::alteration_message('New IMAGE!: ' . $newPath);
111
                    $file = Image::create();
112
                } else {
113
                    DB::alteration_message('New FILE!: ' . $newPath);
114
                    $file = File::create();
115
                }
116
                $file->setFromLocalFile($newPath);
117
                $file->ParentID = $folder->ID;
118
                $file->write();
119
                $file->doPublish();
120
            } else {
121
                DB::alteration_message('existing file: ' . $newPath);
122
            }
123
        }
124
    }
125
126
    protected function getDirContents(string $dir, ?array &$results = [])
127
    {
128
        $files = scandir($dir);
129
130
        foreach ($files as $key => $value) {
131
            $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
132
            if (! is_dir($path)) {
133
                $results[] = $path;
134
            } elseif ('.' !== $value && '..' !== $value) {
135
                $this->getDirContents($path, $results);
136
                $results[] = $path;
137
            }
138
        }
139
140
        return $results;
141
    }
142
143
    protected function isImage(string $newPath): bool
144
    {
145
        $ext = pathinfo(
146
            parse_url($newPath, PHP_URL_PATH),
147
            PATHINFO_EXTENSION
148
        );
149
150
        return in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true);
151
    }
152
153
    protected function normalizePath($path)
154
    {
155
        return $path . (is_dir($path) && ! preg_match('#/$#', $path) ? '/' : '');
156
    }
157
158
    protected function rscandir($dir, $sort = SCANDIR_SORT_ASCENDING)
159
    {
160
        $results = [];
161
162
        if (! is_dir($dir)) {
163
            return $results;
164
        }
165
166
        $dir = $this->normalizePath($dir);
167
168
        $objects = scandir($dir, $sort);
169
170
        foreach ($objects as $object) {
171
            if ('.' !== $object && '..' !== $object) {
172
                if (is_dir($dir . $object)) {
173
                    $results = array_merge($results, $this->rscandir($dir . $object, $sort));
174
                } else {
175
                    $results[] = $dir . $object;
176
                }
177
            }
178
        }
179
180
        $results[] = $dir;
181
182
        return $results;
183
    }
184
185
    protected function rcopy($source, $dest, $destmode = null)
186
    {
187
        if ($this->Config()->get('use_exec_for_copy')) {
188
            exec('cp ' . $source . ' ' . ASSETS_PATH . ' -r');
189
190
            return;
191
        }
192
        $files = $this->rscandir($source);
193
194
        if (empty($files)) {
195
            return;
196
        }
197
198
        if (! file_exists($dest)) {
199
            DB::alteration_message('MKDIR --' . $dest);
200
            mkdir($dest, is_int($destmode) ? $destmode : fileperms($source), true);
201
        }
202
203
        $source = $this->normalizePath(realpath($source));
204
        $dest = $this->normalizePath(realpath($dest));
205
206
        foreach ($files as $file) {
207
            $file_dest = str_replace($source, $dest, $file);
208
            $file = str_replace(' ', ' ', $file);
209
            $file_dest = str_replace(' ', ' ', $file_dest);
210
            if (is_dir($file)) {
211
                if (! file_exists($file_dest)) {
212
                    DB::alteration_message('MKDIR --' . $file_dest);
213
                    mkdir($file_dest, is_int($destmode) ? $destmode : fileperms($file), true);
214
                }
215
            } else {
216
                DB::alteration_message('COPY --' . $file . '-- to --' . $file_dest . '--');
217
                if (file_exists($file)) {
218
                    if (! file_exists($file_dest)) {
219
                        copy($file, $file_dest);
220
                        if (! file_exists($file_dest)) {
221
                            DB::alteration_message('ERROR could not find after copy: --' . $file_dest);
222
                            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
223
                        }
224
                    } else {
225
                        DB::alteration_message('ERROR file already exists: --' . $file_dest);
226
                    }
227
                } else {
228
                    DB::alteration_message('ERROR could not find: --' . $file);
229
                    die('');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
230
                }
231
            }
232
        }
233
    }
234
235
    protected function rrmdir($dir)
236
    {
237
        if (is_dir($dir)) {
238
            $objects = scandir($dir);
239
            foreach ($objects as $object) {
240
                if ('.' !== $object && '..' !== $object) {
241
                    if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && ! is_link($dir . '/' . $object)) {
242
                        $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object);
243
                    } else {
244
                        unlink($dir . DIRECTORY_SEPARATOR . $object);
245
                    }
246
                }
247
            }
248
            rmdir($dir);
249
        }
250
    }
251
}
252