Completed
Push — master ( 55be14...1cd465 )
by satoru
10s
created

ContentsFileBehavior::fileValidationWhen()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 2
1
<?php
2
3
namespace ContentsFile\Model\Behavior;
4
5
use ArrayObject;
6
use Cake\Core\Configure;
7
use Cake\Event\Event;
8
use Cake\Network\Exception\InternalErrorException;
9
use Cake\ORM\Behavior;
10
use Cake\Datasource\EntityInterface;
11
use Cake\ORM\Table;
12
use Cake\ORM\TableRegistry;
13
use ContentsFile\Model\Behavior\Traits\NormalContentsFileBehaviorTrait;
14
use ContentsFile\Model\Behavior\Traits\S3ContentsFileBehaviorTrait;
15
use ContentsFile\Model\Behavior\Traits\ImageContentsFileBehaviorTrait;
16
use Cake\Utility\Security;
17
18
class ContentsFileBehavior extends Behavior {
19
20
    use NormalContentsFileBehaviorTrait;
21
    use S3ContentsFileBehaviorTrait;
22
    use ImageContentsFileBehaviorTrait;
23
24
    /**
25
     * __construct
26
     * @author hagiwara
27
     * @param Table $table
28
     * @param array $config
29
     */
30
    public function __construct(Table $table, array $config = [])
31
    {
32
        parent::__construct($table, $config);
33
        // 指定外のものが指定されている場合はエラーとする
34
        if (!in_array(Configure::read('ContentsFile.Setting.type'), ['s3', 'normal'])) {
35
            throw new InternalErrorException('contentsFileConfig type illegal');
36
        }
37
        // Configureの設定不足をチェックする
38
        $this->{Configure::read('ContentsFile.Setting.type') . 'ParamCheck'}();
39
}
40
41
    /**
42
     * afterSave
43
     * 画像をafterSaveで保存する
44
     * @author hagiwara
45
     * @param Event $event
46
     * @param EntityInterface $entity
47
     * @param ArrayObject $options
48
     */
49
    public function afterSave(Event $event, EntityInterface $entity, ArrayObject $options)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed.

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

Loading history...
50
    {
51
        //設定値をentityから取得
52
        $contentsFileConfig = $entity->getContentsFileSettings();
0 ignored issues
show
Bug introduced by
The method getContentsFileSettings() does not seem to exist on object<Cake\Datasource\EntityInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
53
        $attachmentModel = TableRegistry::get('Attachments');
54
        foreach ($contentsFileConfig['fields'] as $field => $fieldSettings) {
55
            // ファイルの削除を最初に確認
56
            if ($entity->{'delete_' . $field} == true) {
57
                // 該当フィールドを削除
58
                if (!$this->fileDelete($entity, [$field])) {
59
                    return false;
60
                }
61
                // ファイルの削除に成功したら保存処理は飛ばす
62
                continue;
63
            }
64
            //contents_file_の方に入ったentityをベースに処理する
65
            $fileInfo = $entity->{'contents_file_' . $field};
66
            if (
67
                !empty($fileInfo) &&
68
                //tmp_file_nameがある=アップロードしたファイルがある
69
                array_key_exists('tmp_file_name', $fileInfo)
70
            ) {
71
                // ファイルの削除
72
                $attachmentSaveData = [
73
                    'model' => $fileInfo['model'],
74
                    'model_id' => $entity->id,
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
75
                    'field_name' => $fileInfo['field_name'],
76
                    'file_name' => $fileInfo['file_name'],
77
                    'file_content_type' => $fileInfo['file_content_type'],
78
                    'file_size' => $fileInfo['file_size'],
79
                ];
80
                if (Configure::read('ContentsFile.Setting.randomFile') === true) {
81
                    $attachmentSaveData['file_random_path'] = $this->makeRandomPath();
82
                }
83
                $attachmentEntity = $attachmentModel->newEntity($attachmentSaveData);
84
                //元のデータがあるかfind(あれば元のファイルを消す)
85
                $oldAttachmentData = $attachmentModel->find('all')
86
                    ->where(['model' => $fileInfo['model']])
87
                    ->where(['model_id' => $entity->id])
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
88
                    ->where(['field_name' => $fileInfo['field_name']])
89
                    ->first();
90
91
                // 通常とS3で画像保存方法の切り替え
92
                if (!$this->{Configure::read('ContentsFile.Setting.type') . 'FileSave'}($fileInfo, $fieldSettings, $attachmentSaveData, $oldAttachmentData)) {
93
                    return false;
94
                }
95
96
                //元のデータがあれば更新にする
97
                if (!empty($oldAttachmentData)) {
98
                    $attachmentEntity->id = $oldAttachmentData->id;
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
99
                }
100
                if (!$attachmentModel->save($attachmentEntity)) {
101
                    return false;
102
                }
103
            }
104
        }
105
106
        return true;
107
108
    }
109
110
    /**
111
     * fileDelete
112
     * ファイル削除
113
     * @author hagiwara
114
     * @param EntityInterface $entity
115
     * @param array $fields
116
     */
117
    public function fileDelete(EntityInterface $entity, $fields = [])
118
    {
119
        // 新規作成データ時は何もしない
120
        if (empty($entity->id)) {
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
121
            return true;
122
        }
123
        $contentsFileConfig = $entity->getContentsFileSettings();
0 ignored issues
show
Bug introduced by
The method getContentsFileSettings() does not seem to exist on object<Cake\Datasource\EntityInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
124
        if (!empty($contentsFileConfig['fields'])) {
125
            foreach ($contentsFileConfig['fields'] as $field => $config) {
126
                // fieldsの指定がない場合は全部消す
127
                if (!empty($fields) && !in_array($field, $fields)) {
128
                    continue;
129
                }
130
                if (!$this->fileDeleteParts($entity, $field)) {
131
                    return false;
132
                }
133
            }
134
        }
135
        return true;
136
    }
137
138
    /**
139
     * fileValidationWhen
140
     * ファイルのバリデーションのwhenに使用可能なメソッド
141
     * @author hagiwara
142
     * @param array $context
143
     * @param string $field
144
     */
145
    public function fileValidationWhen($context, $field)
146
    {
147
        // content_file_fileがいる場合はチェックしない
148
        if (!empty($context['data']['contents_file_' . $field])) {
149
            return false;
150
        }
151
152
        // 新規作成時はチェックする
153
        if ($context['newRecord'] == true) {
154
            return true;
155
        }
156
        $fileInfo = $this->_table->find('all')
157
            ->where([$this->_table->alias() . '.id' => $context['data']['id']])
158
            ->first();
159
        // 編集時はfileがアップロードされていなければチェックする
160
        return empty($fileInfo->{'contents_file_' . $field});
161
    }
162
163
    /**
164
     * fileDeleteParts
165
     * ファイル削除
166
     * @author hagiwara
167
     * @param EntityInterface $entity
168
     * @param string $field
169
     */
170
    private function fileDeleteParts($entity, $field)
171
    {
172
        $attachmentModel = TableRegistry::get('Attachments');
173
        $modelName = $entity->source();
174
        $modelId = $entity->id;
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
175
        // 添付ファイルデータの削除
176
        $deleteAttachmentData = $attachmentModel->find('all')
177
            ->where(['Attachments.model' => $modelName])
178
            ->where(['Attachments.model_id' => $modelId])
179
            ->where(['Attachments.field_name' => $field])
180
            ->first();
181
182
        if (!empty($deleteAttachmentData->id)) {
183
            // 通常とS3でファイルの削除方法の切り替え
184
            if (!$this->{Configure::read('ContentsFile.Setting.type') . 'FileDelete'}($modelName, $modelId, $field)) {
185
                return false;
186
            }
187
            $attachmentModel->delete($deleteAttachmentData);
188
        }
189
        return true;
190
    }
191
192
    /**
193
     * mkdir
194
     * ディレクトリの作成(パーミッションの設定のため
195
     * @author hagiwara
196
     * @param string $permission
197
     * @param integer $path
198
     * @param boolean $recursive
199
     */
200
    private function mkdir($path, $permission, $recursive)
201
    {
202
        if (is_dir($path)) {
203
            return true;
204
        }
205
        $oldumask = umask(0);
206
        $result = mkdir($path, $permission, $recursive);
207
        umask($oldumask);
208
        return $result;
209
    }
210
211
    /**
212
     * makeRandomKey
213
     * @author hagiwara
214
     */
215
    private function makeRandomPath()
216
    {
217
        $hash = Security::hash(time() . rand());
218
        $attachmentModel = TableRegistry::get('Attachments');
219
        $check = $attachmentModel->find('all')
220
            ->where(['Attachments.file_random_path' => $hash])
221
            ->count();
222
        // データがある場合は再作成
223
        if ($check > 0) {
224
            return $this->makeRandomPath();
225
        }
226
        return $hash;
227
    }
228
}
229