Completed
Push — master ( 6d9f7a...ddd29f )
by Igor
03:01
created

FileBind::updateRelations()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
ccs 11
cts 11
cp 1
rs 9.4285
cc 2
eloc 9
nc 2
nop 3
crap 2
1
<?php
2
3
/**
4
 * @link https://github.com/rkit/filemanager-yii2
5
 * @copyright Copyright (c) 2015 Igor Romanov
6
 * @license [MIT](http://opensource.org/licenses/MIT)
7
 */
8
9
namespace rkit\filemanager\behaviors;
10
11
use Yii;
12
use yii\helpers\ArrayHelper;
13
use yii\db\Query;
14
15
class FileBind
16
{
17 21
    public function bind($model, $attribute, $files)
18
    {
19 21
        $newFiles = $this->newFiles($model, $attribute, $files);
20 21
        if (!count($newFiles)) {
21 2
            return false;
22
        }
23
24 20
        $currentFiles = $this->files($model, $attribute);
25 20
        $currentRelations = $this->relations($model, $attribute);
26 20
        $insertData = $this->prepareInsertRelations($model, $attribute, $newFiles);
27 20
        $updateData = $this->prepareUpdateRelations($model, $attribute, $newFiles, $currentRelations);
28
29 20
        $resultFiles = $insertData['files'] + $updateData['files'];
30 20
        if (!count($resultFiles)) {
31 4
            return false;
32
        }
33
34 20
        $this->delete($model, $attribute, array_diff_key($currentFiles, $resultFiles));
35 20
        $this->save($model, $attribute, $insertData, $updateData, $resultFiles);
36
37 20
        return $resultFiles;
38
    }
39
40 20
    private function save($model, $attribute, $insertData, $updateData, $resultFiles)
41
    {
42 20
        if (count($insertData['rows'])) {
43 20
            $this->insertRelations($model, $attribute, $insertData['rows'], $insertData['columns']);
44 20
        }
45 20
        if (count($updateData['rows'])) {
46 2
            $this->updateRelations($model, $attribute, $updateData['rows']);
47 2
        }
48 20
        if (count($resultFiles)) {
49 20
            $this->updateFiles($model, $attribute, $resultFiles);
50 20
        }
51 20
    }
52
53 21
    private function newFiles($model, $attribute, $fileIds)
54
    {
55 21
        $relation = $model->fileRelation($attribute);
56 21
        $fileModel = $relation->modelClass;
57
58 21
        return $fileModel::find()
59 21
            ->where([key($relation->link) => $fileIds])
60 21
            ->indexBy(key($relation->link))
61 21
            ->all();
62
    }
63
64 20
    private function prepareInsertRelations($model, $attribute, $newFiles)
65
    {
66 20
        $ownerId = $model->getPrimaryKey();
67 20
        $relation = $model->fileRelation($attribute);
68 20
        $uploadedFiles = $model->fileState($attribute);
69 20
        $handlerExtraFields = $model->fileOption($attribute, 'extraFields');
70
71 20
        $files = [];
72 20
        $rows = [];
73 20
        $extraFields = [];
74 20
        foreach ($uploadedFiles as $fileId) {
75 20
            if (isset($newFiles[$fileId])) {
76 20
                $file = $newFiles[$fileId];
77 20
                $row = [$ownerId, $fileId];
78 20
                if ($handlerExtraFields) {
79
                    $fields = [
80 20
                        key($relation->via->link) => $ownerId,
81 20
                        current($relation->link) => $fileId,
82 20
                    ];
83 20
                    $extraFields = $handlerExtraFields($file, $fields);
84 20
                    $row = array_merge($row, array_values($extraFields));
85 20
                }
86 20
                $rows[] = $row;
87 20
                $files[$file->getPrimaryKey()] = $file;
88 20
            }
89 20
        }
90
91 20
        $columns = [key($relation->via->link), current($relation->link)];
92 20
        $columns = array_merge($columns, array_keys($extraFields));
93
94 20
        return ['rows' => $rows, 'files' => $files, 'columns' => $columns];
95
    }
96
97 20
    private function prepareUpdateRelations($model, $attribute, $newFiles, $currentRelations)
98
    {
99 20
        $relation = $model->fileRelation($attribute);
100 20
        $handlerExtraFields = $model->fileOption($attribute, 'extraFields');
101
102 20
        $files = [];
103 20
        $rows = [];
104 20
        foreach ($currentRelations as $fields) {
105 4
            if (isset($newFiles[$fields[current($relation->link)]])) {
106 3
                $file = $newFiles[$fields[current($relation->link)]];
107 3
                if ($handlerExtraFields) {
108 3
                    $extraFields = $handlerExtraFields($file, $fields);
109 3
                    $fieldChanged = (bool)count(array_diff_assoc($extraFields, $fields));
110 3
                    if ($fieldChanged) {
111 2
                        $rows[$file->getPrimaryKey()] = $extraFields;
112 2
                    }
113 3
                }
114 3
                $files[$file->getPrimaryKey()] = $file;
115 3
            }
116 20
        }
117 20
        return ['rows' => $rows, 'files' => $files];
118
    }
119
120 20
    private function insertRelations($model, $attribute, $rows, $columns)
121
    {
122 20
        $relation = $model->fileRelation($attribute);
123 20
        Yii::$app->getDb()->createCommand()
124 20
            ->batchInsert($relation->via->from[0], $columns, $rows)
125 20
            ->execute();
126 20
    }
127
128 2
    private function updateRelations($model, $attribute, $rows)
129
    {
130 2
        $relation = $model->fileRelation($attribute);
131 2
        $ownerId = $model->getPrimaryKey();
132 2
        $db = Yii::$app->getDb()->createCommand();
133
134 2
        foreach ($rows as $fileId => $row) {
135 2
            $db->update($relation->via->from[0], $row, [
136 2
                key($relation->via->link) => $ownerId,
137 2
                current($relation->link) => $fileId
138 2
            ])->execute();
139 2
        }
140 2
    }
141
142 20
    private function updateFiles($model, $attribute, $files)
143
    {
144 20
        $handlerUpdateFile = $model->fileOption($attribute, 'updateFile');
145 20
        if ($handlerUpdateFile) {
146 20
            foreach ($files as $file) {
147 20
                $fileUpd = $handlerUpdateFile($file);
148 20
                $dirtyAttributes = $fileUpd->getDirtyAttributes();
149 20
                if (count($dirtyAttributes)) {
150 1
                    $fileUpd->updateAttributes($dirtyAttributes);
151 1
                }
152 20
            }
153 20
        }
154 20
    }
155
156 21
    public function delete($model, $attribute, $files)
157
    {
158 21
        $relation = $model->fileRelation($attribute);
159 21
        $storage = $model->fileStorage($attribute);
160 21
        $presets = array_keys($model->fileOption($attribute, 'preset', []));
161 21
        $handlerTemplatePath = $model->fileOption($attribute, 'templatePath');
162
163 21
        $db = Yii::$app->getDb()->createCommand();
164 21
        foreach ($files as $file) {
165 4
            foreach ($presets as $preset) {
166 4
                $thumbPath = $model->thumbPath($attribute, $preset, $file);
167 4
                $filePath = str_replace($storage->path, '', $thumbPath);
168 4
                if ($storage->has($filePath)) {
169 4
                    $storage->delete($filePath);
170 4
                }
171 4
            }
172 4
            if ($file->delete()) {
173 4
                $db->delete($relation->via->from[0], [
174 4
                    current($relation->link) => $file->getPrimaryKey()
175 5
                ])->execute();
176 4
                $filePath = $handlerTemplatePath($file);
177 4
                if ($storage->has($filePath)) {
178 4
                    $storage->delete($filePath);
179 4
                }
180 4
            }
181 21
        }
182 21
    }
183
184 20
    public function relations($model, $attribute)
185
    {
186 20
        $relation = $model->fileRelation($attribute);
187 20
        $handlerRelationQuery = $model->fileOption($attribute, 'relationQuery');
188 20
        $query = null;
189
190 20
        if ($handlerRelationQuery) {
191 20
            $query = Query::create($handlerRelationQuery($model->find()));
192 20
        }
193
194 20
        $query = $query ?: new Query();
195
        return $query
196 20
            ->from($relation->via->from[0])
197 20
            ->andWhere([key($relation->via->link) => $model->getPrimaryKey()])
198 20
            ->indexBy(current($relation->link))
199 20
            ->all();
200
    }
201
202 22
    public function files($model, $attribute)
203
    {
204 22
        $relation = $model->fileRelation($attribute);
205 22
        $relationName = $model->fileOption($attribute, 'relation');
206 22
        $handlerRelationQuery = $model->fileOption($attribute, 'relationQuery');
207
208 22
        $query = call_user_func_array([$model, 'get' . $relationName], [$handlerRelationQuery]);
209 22
        return $query->indexBy(key($relation->link))->all();
210
    }
211
212 12
    public function file($model, $attribute)
213
    {
214 12
        $relation = $model->fileOption($attribute, 'relation');
215 12
        $handlerRelationQuery = $model->fileOption($attribute, 'relationQuery');
216
217 12
        $query = call_user_func_array([$model, 'get' . $relation], [$handlerRelationQuery]);
218 12
        return $query->one();
219
    }
220
}
221