Completed
Push — master ( ab3f3f...fb408b )
by Nicolaas
02:01
created

PerfectCMSImagesUploadField::flush()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 24
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.5125
c 0
b 0
f 0
cc 5
eloc 10
nc 7
nop 0
1
<?php
2
3
/**
4
 * image-friendly upload field.
5
6
 * Usage:
7
 *     $field = PerfectCMSImagesUploadFielde::create(
8
 *         "ImageField",
9
 *         "Add Image",
10
 *         null,
11
 *         300,
12
 * 	       "anything you like",
13
 *         "folder-name",
14
 *         "png or jpg"
15
 * 	);
16
 */
17
class PerfectCMSImagesUploadField extends UploadField implements flushable
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...
18
{
19
    private static $max_size_in_kilobytes = 1024;
0 ignored issues
show
Unused Code introduced by
The property $max_size_in_kilobytes is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
20
21
    /**
22
     * @param string  $name
23
     * @param string  $title
24
     * @param SS_List $items If no items are defined, the field will try to auto-detect an existing relation
0 ignored issues
show
Documentation introduced by
Should the type for parameter $items not be null|SS_List?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
25
     *
26
     * @return UploadField
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
27
     */
28
    public function __construct(
29
        $name,
30
        $title,
31
        SS_List $items = null
32
    ) {
33
        parent::__construct(
34
            $name,
35
            $title,
36
            $items
37
        );
38
        $perfectCMSImageValidator = new PerfectCMSImage_Validator();
39
        $this->setValidator($perfectCMSImageValidator);
40
        $this->selectFormattingStandard($name);
41
        return $this;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
42
    }
43
44
    public function setRightTitle($string)
45
    {
46
        parent::setRightTitle(
47
            $string.
48
            '<br />'.
49
            $this->RightTitle()
50
        );
51
        //important!
52
        return $this;
53
    }
54
55
    /**
56
     *
57
     *
58
     *
59
     * @param  string $name Formatting Standard
60
     * @return this
0 ignored issues
show
Documentation introduced by
Should the return type not be PerfectCMSImagesUploadField?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
61
     */
62
    public function selectFormattingStandard($name)
63
    {
64
        parent::setRightTitle('');
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setRightTitle() instead of selectFormattingStandard()). Are you sure this is correct? If so, you might want to change this to $this->setRightTitle().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
65
        $widthRecommendation = PerfectCMSImageDataExtension::get_width($name);
66
        $heightRecommendation = PerfectCMSImageDataExtension::get_height($name);
67
        $folderName = PerfectCMSImageDataExtension::get_folder($name);
68
        if (!$folderName) {
69
            $folderName = 'other-images';
70
        }
71
        $recommendedFileType = PerfectCMSImageDataExtension::get_file_type($name);
72
        if (!$recommendedFileType) {
73
            $recommendedFileType = 'jpg';
74
        }
75
        $folderName = 'Uploads/'.$folderName.'/';
76
        if ($widthRecommendation) {
77
            if (intval($widthRecommendation)) {
78
                //cater for retina
79
                $widthRecommendation = $widthRecommendation * 2;
80
                $actualWidthDescription = $widthRecommendation.'px';
81
            } else {
82
                $actualWidthDescription = $widthRecommendation;
83
            }
84
        } else {
85
            $actualWidthDescription = 'flexible';
86
        }
87
        if ($heightRecommendation) {
88
            if (intval($heightRecommendation)) {
89
                //cater for retina
90
                $heightRecommendation = $heightRecommendation * 2;
91
                $actualHeightDescription = $heightRecommendation.'px';
92
            } else {
93
                $actualHeightDescription = $heightRecommendation;
94
            }
95
        } else {
96
            $actualHeightDescription = 'flexible';
97
        }
98
99
100
        $rightTitle = "";
101
102
        if ($actualWidthDescription == 'flexible') {
103
            $rightTitle .= 'Image width is flexible, and ';
104
        } else {
105
            $rightTitle .= "Image should be <strong>$actualWidthDescription</strong> wide and ";
106
        }
107
108
109
        if ($actualHeightDescription == 'flexible') {
110
            $rightTitle .= 'image height is flexible, and ';
111
        } else {
112
            $rightTitle .= "image should be <strong>$actualHeightDescription</strong> high and ";
113
        }
114
115
        $rightTitle .= 'the image should be less than 1MB in size. <br/>
116
            The recommend file type (file extension) is <strong>'.$recommendedFileType.'</strong>.
117
            ';
118
119
120
        parent::setRightTitle($rightTitle);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setRightTitle() instead of selectFormattingStandard()). Are you sure this is correct? If so, you might want to change this to $this->setRightTitle().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
121
122
        //create folder
123
        Folder::find_or_make($folderName);
124
        //set folder
125
        $this->setFolderName($folderName);
126
        $this->setAllowedFileCategories('image');
127
        $alreadyAllowed = $this->getAllowedExtensions();
128
        $this->setAllowedExtensions($alreadyAllowed + array('svg'));
129
        //keep the size reasonable
130
        $this->getValidator()->setAllowedMaxFileSize(1 * 1024 * Config::inst()->get('PerfectCMSImagesUploadFieldeProvider', 'max_size_in_kilobytes'));
131
        $this->getValidator()->setFieldName($name);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Upload_Validator as the method setFieldName() does only exist in the following sub-classes of Upload_Validator: PerfectCMSImage_Validator. 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...
132
        return $this;
133
    }
134
135
    public static function flush() {
136
        if(ASSETS_PATH) {
137
            if(! file_exists(ASSETS_PATH)) {
138
                Filesystem::makeFolder(ASSETS_PATH);
139
            }
140
            $fileName = ASSETS_PATH.'/.htaccess';
141
            if(! file_exists($fileName)) {
142
                $string = '
143
<IfModule mod_rewrite.c>
144
    RewriteEngine On
145
    RewriteBase /
146
147
    RewriteCond %{REQUEST_FILENAME} !-f
148
    RewriteCond %{REQUEST_FILENAME} !-d
149
    RewriteRule ^(.+)\.(v[A-Za-z0-9]+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
150
</IfModule>
151
                ';
152
                if(!file_exists(ASSETS_PATH)) {
153
                    Filesystem::makeFolder(ASSETS_PATH);
154
                }
155
                file_put_contents($fileName, $string);
156
            }
157
        }
158
    }
159
160
}
161