Completed
Push — master ( 34e737...1a9402 )
by Nicolaas
01:42
created

ImageStyle::validate()   C

Complexity

Conditions 11
Paths 2

Size

Total Lines 45
Code Lines 32

Duplication

Lines 45
Ratio 100 %

Importance

Changes 0
Metric Value
dl 45
loc 45
c 0
b 0
f 0
rs 5.2653
cc 11
eloc 32
nc 2
nop 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
4
5
class ImageStyle extends DataObject
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
6
{
7
8
9
    /**
10
     * see _config folder for details ...
11
     * @var array
12
     */
13
    private static $record_defaults = [];
14
15
16
    #######################
17
    ### Names Section
18
    #######################
19
20
    private static $singular_name = 'Image Style';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
21
22
    function i18n_singular_name()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
23
    {
24
        return _t('ImageStyle.SINGULAR_NAME', 'Image Style');
25
    }
26
27
    private static $plural_name = 'Image Styles';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
28
29
    function i18n_plural_name()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
30
    {
31
        return _t('ImageStyle.PLURAL_NAME', 'Image Styles');
32
    }
33
34
35
    #######################
36
    ### Model Section
37
    #######################
38
39
    private static $db = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
40
        'Title' => 'Varchar',
41
        'ClassNameForCSS' => 'Varchar',
42
        'Description' => 'Text',
43
        'Var1Name' => 'Varchar',
44
        'Var1Type' => 'Enum(\'Pixels,Percentage,Options\', \'Pixels\')',
45
        'Var1Options' => 'Varchar(200)',
46
        'Var1Description' => 'Varchar(200)',
47
48
        'Var2Name' => 'Varchar',
49
        'Var2Type' => 'Enum(\'Pixels,Percentage,Options\', \'Pixels\')',
50
        'Var2Options' => 'Varchar(200)',
51
        'Var2Description' => 'Varchar(200)',
52
53
        'Var3Name' => 'Varchar',
54
        'Var3Type' => 'Enum(\'Pixels,Percentage,Options\', \'Pixels\')',
55
        'Var3Options' => 'Varchar(200)',
56
        'Var3Description' => 'Varchar(200)',
57
58
        'Var4Name' => 'Varchar',
59
        'Var4Type' => 'Enum(\'Pixels,Percentage,Options\', \'Pixels\')',
60
        'Var4Options' => 'Varchar(200)',
61
        'Var4Description' => 'Varchar(200)',
62
63
        'Var5Name' => 'Varchar',
64
        'Var5Type' => 'Enum(\'Pixels,Percentage,Options\', \'Pixels\')',
65
        'Var5Options' => 'Varchar(200)',
66
        'Var5Description' => 'Varchar(200)',
67
68
    ];
69
70
    private static $has_many = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
71
        'ImagesWithStyle' => 'ImageWithStyle'
72
    ];
73
74
75
    #######################
76
    ### Further DB Field Details
77
    #######################
78
79
    private static $indexes = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
80
        'Title' => true
81
    ];
82
83
    private static $default_sort = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
84
        'Title' => 'ASC'
85
    ];
86
87
    private static $required_fields = [
88
        'Title',
89
        'ClassNameForCSS'
90
    ];
91
92
    private static $searchable_fields = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
93
        'Title' => 'PartialMatchFilter',
94
        'Description' => 'PartialMatchFilter',
95
        'ClassNameForCSS' => 'PartialMatchFilter'
96
    ];
97
98
99
    #######################
100
    ### Field Names and Presentation Section
101
    #######################
102
103
    private static $field_labels = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
104
        'Title' => 'Style',
105
106
        'Var1Name' => 'Variable 1 Label',
107
        'Var1Type' => 'Variable 1 Type',
108
        'Var1Options' => 'Variable 1 Options',
109
        'Var1Description' => 'Variable 1 Description',
110
111
        'Var2Name' => 'Variable 2 Label',
112
        'Var2Type' => 'Variable 2 Type',
113
        'Var2Options' => 'Variable 1 Options',
114
        'Var2Description' => 'Variable 1 Description',
115
116
        'Var3Name' => 'Variable 3 Label',
117
        'Var3Type' => 'Variable 3 Type',
118
        'Var3Options' => 'Variable 1 Options',
119
        'Var4Description' => 'Variable 1 Description',
120
121
        'Var4Name' => 'Variable 4 Label',
122
        'Var4Type' => 'Variable 4 Type',
123
        'Var4Options' => 'Variable 4 Options',
124
        'Var4Description' => 'Variable 4 Description',
125
126
        'Var5Name' => 'Variable 5 Label',
127
        'Var5Type' => 'Variable 5 Type',
128
        'Var5Options' => 'Variable 5 Options',
129
        'Var5Description' => 'Variable 5 Description',
130
    ];
131
132
    private static $field_labels_right = [];
133
134
    private static $summary_fields = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
135
        'Title' => 'Style',
136
        'ImagesWithStyle.Count' => 'Usage Count'
137
    ];
138
139
140
    #######################
141
    ### Casting Section
142
    #######################
143
144
145
    #######################
146
    ### can Section
147
    #######################
148
149
    function canCreate($member = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
150
    {
151
        return false;
152
    }
153
154
    function canEdit($member = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
155
    {
156
        //we block edits in CMS
157
        return parent::canEdit($member);
158
    }
159
160
    function canDelete($member = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
161
    {
162
        if($this->ImagesWithStyle()->count() === 0 ) {
0 ignored issues
show
Documentation Bug introduced by
The method ImagesWithStyle does not exist on object<ImageStyle>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
163
164
            return parent::canDelete($member);
165
        }
166
167
        return false;
168
    }
169
170
171
172
    #######################
173
    ### write Section
174
    #######################
175
176
177
178
179 View Code Duplication
    public function validate()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
    {
181
        $result = parent::validate();
182
        $fieldLabels = $this->FieldLabels();
183
        $indexes = $this->Config()->get('indexes');
184
        $requiredFields = $this->Config()->get('required_fields');
185
        if(is_array($requiredFields)) {
186
            foreach($requiredFields as $field) {
187
                $value = $this->$field;
188
                if(! $value) {
189
                    $fieldWithoutID = $field;
190
                    if(substr($fieldWithoutID, -2) === 'ID') {
191
                        $fieldWithoutID = substr($fieldWithoutID, 0, -2);
192
                    }
193
                    $myName = isset($fieldLabels[$fieldWithoutID]) ? $fieldLabels[$fieldWithoutID] : $fieldWithoutID;
194
                    $result->error(
195
                        _t(
196
                            'ImageStyle.'.$field.'_REQUIRED',
197
                            $myName.' is required'
198
                        ),
199
                        'REQUIRED_ImageStyle_'.$field
200
                    );
201
                }
202
                if (isset($indexes[$field]) && isset($indexes[$field]['type']) && $indexes[$field]['type'] === 'unique') {
203
                    $id = (empty($this->ID) ? 0 : $this->ID);
204
                    $count = ImageStyle::get()
205
                        ->filter(array($field => $value))
206
                        ->exclude(array('ID' => $id))
207
                        ->count();
208
                    if($count > 0) {
209
                        $myName = $fieldLabels['$field'];
210
                        $result->error(
211
                            _t(
212
                                'ImageStyle.'.$field.'_UNIQUE',
213
                                $myName.' needs to be unique'
214
                            ),
215
                            'UNIQUE_ImageStyle_'.$field
216
                        );
217
                    }
218
                }
219
            }
220
        }
221
222
        return $result;
223
    }
224
225
    public function onBeforeWrite()
226
    {
227
        parent::onBeforeWrite();
228
        $this->ClassNameForCSS = preg_replace('/\W+/','-',strtolower(strip_tags($this->ClassNameForCSS)));
0 ignored issues
show
Bug introduced by
The property ClassNameForCSS does not seem to exist. Did you mean ClassName?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
229
        if(! $this->ClassNameForCSS) {
0 ignored issues
show
Bug introduced by
The property ClassNameForCSS does not seem to exist. Did you mean ClassName?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
230
            $this->ClassNameForCSS = 'image-with-style-'.$this->ID;
0 ignored issues
show
Bug introduced by
The property ClassNameForCSS does not seem to exist. Did you mean ClassName?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
231
        }
232
        //...
233
    }
234
235
    public function onAfterWrite()
236
    {
237
        parent::onAfterWrite();
238
        //...
239
    }
240
241
    public function requireDefaultRecords()
242
    {
243
        parent::requireDefaultRecords();
244
        //...
245
        $defaults = $this->Config()->record_defaults;
246
        $currentOnes = array_flip(ImageStyle::get()->column('ID'));
247
        $imageNames = Config::inst()->get('PerfectCMSImageDataExtension', 'perfect_cms_images_image_definitions');
248
        foreach($defaults as $defaultValues) {
249
            foreach($defaultValues as $field => $value) {
250
                if(is_array($value)) {
251
                    $defaultValues[$field] = serialize($value);
252
                }
253
            }
254
            $obj = ImageStyle::get()->filter(['Title' => $defaultValues['Title']])->first();
255
            if(!$obj) {
256
                $obj = ImageStyle::create($defaultValues);
257
            } else {
258
                foreach($obj->db() as $field => $type) {
259
                    $obj->$field = null;
260
                }
261
                foreach($defaultValues as $field => $value) {
262
                    $obj->$field = $value;
263
                }
264
            }
265
            unset($currentOnes[$obj->ID]);
266
            $obj->write();
267
            if(! isset($imageNames[$obj->ClassNameForCSS])) {
0 ignored issues
show
Bug introduced by
The property ClassNameForCSS does not seem to exist. Did you mean ClassName?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
268
                user_error('You need to define a perfect CMS image with the following name: '.$obj->ClassNameForCSS);
0 ignored issues
show
Bug introduced by
The property ClassNameForCSS does not seem to exist. Did you mean ClassName?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
269
            }
270
271
        }
272
        foreach($currentOnes as $id) {
273
            $obj = ImageStyle::get()->byID($id);
274
            if($obj->canDelete()) {
275
                $obj->delete();
276
            }
277
        }
278
    }
279
280
281
    #######################
282
    ### Import / Export Section
283
    #######################
284
285
    public function getExportFields()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
286
    {
287
        //..
288
        return parent::getExportFields();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class DataObject as the method getExportFields() does only exist in the following sub-classes of DataObject: ImageStyle, ImageWithStyle, ImagesWithStyleSelection. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
289
    }
290
291
292
293
    #######################
294
    ### CMS Edit Section
295
    #######################
296
297
298
    public function CMSEditLink()
299
    {
300
        $controller = singleton("tba");
301
302
        return $controller->Link().$this->ClassName."/EditForm/field/".$this->ClassName."/item/".$this->ID."/edit";
303
    }
304
305
    public function CMSAddLink()
306
    {
307
        $controller = singleton("tba");
308
309
        return $controller->Link().$this->ClassName."/EditForm/field/".$this->ClassName."/item/new";
310
    }
311
312
313
    public function getCMSFields()
314
    {
315
        $fields = parent::getCMSFields();
316
317
        //do first??
318
        $rightFieldDescriptions = $this->Config()->get('field_labels_right');
319 View Code Duplication
        foreach($rightFieldDescriptions as $field => $desc) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
320
            $formField = $fields->DataFieldByName($field);
321
            if(! $formField) {
322
                $formField = $fields->DataFieldByName($field.'ID');
323
            }
324
            if($formField) {
325
                $formField->setDescription($desc);
326
            }
327
        }
328
329
        // move variables to their own tab
330
        for($i = 1; $i < 6; $i++) {
331
            if($this->HasStyleVariable('Var'.$i)) {
332
                $fieldsToAdd = [
333
                    $fields->dataFieldByName('Var'.$i.'Name'),
334
                    $fields->dataFieldByName('Var'.$i.'Type'),
335
                    $fields->dataFieldByName('Var'.$i.'Options'),
336
                    $fields->dataFieldByName('Var'.$i.'Description')
337
                ];
338
                $fields->addFieldsToTab(
339
                    'Root.Variable '.$i,
340
                    $fieldsToAdd
341
                );
342
            } else {
343
                $fields->removeByName('Var'.$i.'Name');
344
                $fields->removeByName('Var'.$i.'Type');
345
                $fields->removeByName('Var'.$i.'Options');
346
                $fields->removeByName('Var'.$i.'Description');
347
            }
348
        }
349
        $fields->removeByName('ImagesWithStyle');
350
351
        //make everything readonly
352
        foreach($fields->saveableFields() as $field) {
353
            $fieldName = $field->getName();
354
            $oldField = $fields->dataFieldByName($fieldName);
355
            if ($oldField) {
356
                $newField = $oldField->performReadonlyTransformation();
357
                $fields->replaceField($fieldName, $newField);
358
            }
359
        }
360
361
        return $fields;
362
    }
363
364
365
    public function HasStyleVariable($varName)
366
    {
367
        $name = $varName.'Name';
368
        $type = $varName.'Type';
369
        $hasBase = $this->$name && $this->$type ? true : false;
370
        if($this->$type === 'Options') {
371
            return $hasBase && is_array($this->OptionsAsArray($varName)) ? true : false;
372
        } else {
373
374
            return $hasBase;
375
        }
376
377
    }
378
    public function HasOptionsAsArray($varName)
379
    {
380
        $options = $this->OptionsAsArray($varName);
381
382
        return count($options) ? true : false;
383
    }
384
385
    public function OptionsAsArray($varName) : array
386
    {
387
        $options = $varName.'Options';
388
        $array = [];
389
        if($this->$options) {
390
            $array = @unserialize($this->$options);
391
        }
392
        if(is_array($array)) {
393
            return $array;
394
        }
395
396
        return [];
397
    }
398
399
400
}
401