ImagesManager::prepareImageData()   F
last analyzed

Complexity

Conditions 21
Paths > 20000

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
nc 65536
nop 3
dl 0
loc 26
rs 0
c 0
b 0
f 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
namespace xbanners\src\Managers;
4
5
use Propel\Runtime\Exception\PropelException;
6
use xbanners\models\BannerImageI18nQuery;
7
use xbanners\models\BannerImageQuery;
8
use xbanners\models\Base\Banners;
9
use CI;
10
use DirectoryIterator;
11
use Exception;
12
use MY_Controller;
13
use Propel\Runtime\ActiveQuery\Criteria;
14
15
/**
16
 * User: mark
17
 * Date: 19.03.15
18
 * Time: 15:46
19
 */
20
class ImagesManager
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
21
{
22
23
    /**
24
     * Path name for origins images folder without uploads path
25
     */
26
    const IMAGES_ORIGIN_DIR_PATH = '/uploads/images/bimages/';
27
28
    /**
29
     * Path name for origins images folder without uploads path
30
     */
31
    const IMAGES_TUNED_DIR_PATH = '/uploads/banners/tuned/';
32
33
    /**
34
     * Image file input name
35
     */
36
    const IMAGE_FILE_FIELD = 'file-image';
37
38
    /**
39
     * Image upload file allowed types
40
     */
41
    const IMAGES_UPLOAD_ALLOWED_TYPES = 'jpg|gif|png|jpeg';
42
43
    /**
44
     * Image file max size
45
     */
46
    const IMAGE_MAX_SIZE = '51200';
47
48
    /**
49
     * @var ImagesManager instance
50
     */
51
    private static $instance = NULL;
52
53
    private function __construct() {
54
55
    }
56
57
    /**
58
     * Get ImagesManager instance
59
     * @return ImagesManager instance
60
     */
61
    public static function getInstance() {
62
        if (self::$instance === null) {
63
            self::$instance = new self();
64
        }
65
        return self::$instance;
66
    }
67
68
    /**
69
     * Delete images if they not used
70
     * @deprecated
71
     */
72
    public function deleteNotExistingImages() {
73
        $images = BannerImageI18nQuery::create()->setComment(__METHOD__)->find();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Propel\Runtime\ActiveQuery\Criteria as the method find() does only exist in the following sub-classes of Propel\Runtime\ActiveQuery\Criteria: Propel\Runtime\ActiveQuery\ModelCriteria, core\models\Base\RouteQuery, core\models\RouteQuery, xbanners\models\BannerImageI18nQuery, xbanners\models\BannerImageQuery, xbanners\models\BannersI18nQuery, xbanners\models\BannersQuery, xbanners\models\Base\BannerImageI18nQuery, xbanners\models\Base\BannerImageQuery, xbanners\models\Base\BannersI18nQuery, xbanners\models\Base\BannersQuery. 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...
74
75
        $imagesSrc = [];
76
        foreach ($images as $image) {
77
            $imagesSrc[$image->getSrc()] = $image;
78
        }
79
80
        foreach (new DirectoryIterator('.' . self::IMAGES_ORIGIN_DIR_PATH) as $imageFile) {
81
            if (!$imageFile->isDot() && $imageFile->isFile()) {
82
                if (!$imagesSrc[$imageFile->getFilename()]) {
83
                    $this->deleteImageFile('.' . self::IMAGES_ORIGIN_DIR_PATH . $imageFile->getFilename());
84
                }
85
            }
86
        }
87
    }
88
89
    /** Get tuned image path
90
     * @param string $image_name - banner image name
91
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

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...
92
     */
93
    public function getImageOriginPath($image_name = NULL) {
94
95
        if ($image_name) {
96
97
            $path1 = ltrim(self::IMAGES_ORIGIN_DIR_PATH, '/') . $image_name;
98
            $fullPath1 = FCPATH . $path1;
99
100
            if (file_exists($fullPath1)) {
101
                return '/' . $path1;
102
            }
103
104
            $path2 = 'uploads/banners/origins/' . $image_name;
105
            $fullPath2 = FCPATH . $path2;
106
            if (file_exists($fullPath2)) {
107
                return '/' . $path2;
108
            }
109
            return $image_name ? self::IMAGES_ORIGIN_DIR_PATH . $image_name : NULL;
110
        }
111
112
    }
113
114
    /** Get origin image path
115
     * @param string $image_name - banner image name
116
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

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...
117
     */
118
    public function getImageTunedPath($image_name = NULL) {
119
        return $image_name ? self::IMAGES_TUNED_DIR_PATH . $image_name : NULL;
120
    }
121
122
    /**
123
     * Delete image files: origin image and tuned image from uploads
124
     * @param int $imageId
125
     * @param null|string $locale
126
     * @return bool
127
     * @throws PropelException
128
     */
129
    public function delete($imageId, $locale = NULL) {
130
        if (!$imageId) {
131
            return FALSE;
132
        }
133
134
        $images = BannerImageQuery::create()
135
            ->_if($locale)
0 ignored issues
show
Documentation introduced by
$locale is of type null|string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
136
            ->joinWithI18n($locale)
137
            ->_endif()
138
            ->findPk($imageId);
139
140
        if (!$images) {
141
            return FALSE;
142
        }
143
144
        foreach ($images->getBannerImageI18ns() as $image) {
145
            $image_path = '.' . self::IMAGES_ORIGIN_DIR_PATH . $image->getSrc();
146
            $image->setSrc(NULL);
147
            $image->save();
148
149
            $this->deleteImageFile($image_path);
150
        }
151
152
        return TRUE;
153
    }
154
155
    /**
156
     * Delete image file
157
     * @param string $image_path - path to image file
158
     * @return bool
159
     */
160
    private function deleteImageFile($image_path) {
161
        if (file_exists($image_path) && is_file($image_path)) {
162
            chmod($image_path, 0777);
163
            return unlink($image_path);
164
        }
165
        return FALSE;
166
    }
167
168
    /**
169
     * @param string $path
170
     */
171
    protected function buildImagePath($path) {
172
        $buildPath = '';
173
        foreach (explode('/', $path) as $part) {
174
            if ($part != '') {
175
                $buildPath .= $part . '/';
176
                file_exists($buildPath) || mkdir($buildPath) && chmod($buildPath, 0777);
177
            }
178
        }
179
    }
180
181
    /**
182
     * Save image file
183
     * @param $imageId
184
     * @param $locale
185
     * @return string
186
     * @throws Exception
187
     */
188
    public function saveImage($imageId = NULL, $locale = NULL) {
189
190
        if (!file_exists(self::IMAGES_ORIGIN_DIR_PATH)) {
191
            $this->buildImagePath(self::IMAGES_ORIGIN_DIR_PATH);
192
        }
193
194
        $config['upload_path'] = rtrim(PUBPATH, '/') . self::IMAGES_ORIGIN_DIR_PATH;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$config was never initialized. Although not strictly required by PHP, it is generally a good practice to add $config = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
195
        $config['allowed_types'] = self::IMAGES_UPLOAD_ALLOWED_TYPES;
196
        $config['max_size'] = self::IMAGE_MAX_SIZE;
197
198
        CI::$APP->load->library('upload', $config);
199
200
        if (!CI::$APP->upload->do_upload(self::IMAGE_FILE_FIELD)) {
201
            throw new Exception(strip_tags(CI::$APP->upload->display_errors()));
202
        } else {
203
            if ($imageId && $locale) {
204
                $this->delete($imageId, $locale);
205
            }
206
207
            $data = CI::$APP->upload->data();
208
209
            $imageFileName = time() . $data['file_ext'];
210
            $imageFilePath = $data['file_path'] . $imageFileName;
211
            chmod($data['full_path'], 0777);
212
            copy($data['full_path'], $imageFilePath);
213
            chmod($imageFilePath, 0777);
214
            unlink($data['full_path']);
215
216
            return $imageFileName;
217
        }
218
    }
219
220
    /**
221
     * Upload image
222
     * @throws \Exception
223
     */
224
    public function uploadImage() {
225
        $_POST['maximumSize'] = self::IMAGE_MAX_SIZE;
226
227
        if ($this->checkImageUploadErrors()) {
228
            try {
229
                $pictureCut = \PictureCut::createSingleton();
230
231
                if ($pictureCut->upload()) {
232
                    echo $pictureCut->toJson();
233
                } else {
234
                    echo $pictureCut->exceptionsToJson();
235
                }
236
            } catch (Exception $e) {
237
                echo $e->getMessage();
238
            }
239
        }
240
    }
241
242
    /**
243
     * Check on errors exists while upload file
244
     * @return bool
245
     */
246
    private function checkImageUploadErrors() {
247
        $file = $_FILES[self::IMAGE_FILE_FIELD];
248
        $fileSize = round($file['size'] / 1024);
249
250
        if (!strstr($file['type'], self::IMAGES_UPLOAD_ALLOWED_TYPES)) {
251
            $error_message = lang('You can upload only images', 'xbanners');
252
        }
253
254
        if ($fileSize > self::IMAGE_MAX_SIZE) {
255
            $error_message = lang('You can not upload file with size more than:', 'xbanners') . ' ' . self::IMAGE_MAX_SIZE . 'KB';
256
        }
257
258
        if ($error_message) {
259
            echo json_encode(
260
                [
261
                 'status'       => false,
262
                 'errorMessage' => $error_message,
263
                ]
264
            );
265
266
            return FALSE;
267
        }
268
269
        return TRUE;
270
    }
271
272
    /**
273
     * Get images ordered by page types
274
     * @param Banners $banner - banner object
275
     * @param string $locale - locale name
276
     * @return array
277
     */
278
    public function getImagesByPageType($banner, $locale) {
279
        $pages = BannerPageTypesManager::getInstance()->getPages($banner->getPageType(), $locale);
280
281
        $orderCriteria = new Criteria();
282
        $orderCriteria->addDescendingOrderByColumn('Position');
283
284
        $images = $banner->getBannerImages($orderCriteria);
285
286
        if ($pages === null && count($images)) {
287
            $pagesGroupName = lang('Images', 'xbanners');
288
            $resultImages[$pagesGroupName]['images'] = [];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$resultImages was never initialized. Although not strictly required by PHP, it is generally a good practice to add $resultImages = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
289
290 View Code Duplication
            foreach ($images as $image) {
291
                $image->setLocale($locale);
292
                if ($image->getActive()) {
293
                    $resultImages[$pagesGroupName]['images'][] = $image;
294
                }
295
            }
296
297 View Code Duplication
            foreach ($images as $image) {
298
                $image->setLocale($locale);
299
                if (!$image->getActive()) {
300
                    array_push($resultImages[$pagesGroupName]['images'], $image);
301
                }
302
            }
303
            return $resultImages;
304
        }
305
306
        $resultImages = [];
307
        foreach ($images as $image) {
308
            $image->setLocale($locale);
309
            $imagePage = $pages[$image->getAllowedPage()];
310
            $pagesGroupName = $imagePage['name'] ? $imagePage['name'] : lang('Images without relation', 'xbanners');
311
            $resultImages[$pagesGroupName]['images'] = $resultImages[$pagesGroupName]['images'] ? $resultImages[$pagesGroupName]['images'] : [];
312
313
            if ($image->getActive()) {
314
                $resultImages[$pagesGroupName]['images'][] = $image;
315
            }
316
        }
317
318
        foreach ($images as $image) {
319
            $image->setLocale($locale);
320
            $imagePage = $pages[$image->getAllowedPage()];
321
            $pagesGroupName = $imagePage['name'] ? $imagePage['name'] : lang('Images without relation', 'xbanners');
322
323
            if (!$image->getActive()) {
324
                array_push($resultImages[$pagesGroupName]['images'], $image);
325
            }
326
        }
327
328
        return $resultImages;
329
    }
330
331
    /**
332
     * Prepare banner image data for save into DB
333
     * @param array $data - image data array
334
     * @param $bannerId - banner id
335
     * @param $locale - locale name
336
     * @return array
337
     */
338
    public function prepareImageData(array $data, $bannerId, $locale) {
339
        $host = CI::$APP->input->server('HTTP_HOST');
340
341
        $data['url'] = (false === strpos($data['url'], $host)) ? $data['url'] : preg_replace("/^(https?:\/\/)?$host\/?/i", '/', $data['url']);
342
        $data['url'] = strstr($data['url'], 'http') || $data['url'][0] === '/' ? $data['url'] : '' . $data['url'];
343
344
        $data['allowed_page'] = !$data['allowed_page_all'] && $data['allowed_page'] ? (int) $data['allowed_page'] : 0;
345
        $data['target'] = $data['target'] ? 1 : 0;
346
        $data['permanent'] = $data['permanent'] ? 1 : 0;
347
        $data['active'] = isset($data['active']) ? 1 : 0;
348
        $data['active_from'] = $data['active_from'] && !$data['permanent'] ? strtotime($data['active_from']) : NULL;
349
        //        $data['active_from'] = $data['active_to'] && !$data['active_from'] ? time() : $data['active_from'];
350
        $data['active_to'] = $data['active_to'] && !$data['permanent'] ? strtotime($data['active_to']) : NULL;
351
352
        if (($data['active_from'] > $data['active_to'] && ($data['active_from'] && $data['active_to']))
353
            || ((time() > $data['active_to']) && $data['active_to'])
354
        ) {
355
            $data['active'] = 0;
356
        }
357
        $data['banner_id'] = $bannerId;
358
        $data['locale'] = $locale ? $locale : MY_Controller::defaultLocale();
359
        $data['src'] = $data['src'] ? $data['src'] : NULL;
360
        $data['clicks'] = $data['clicks'] ? (int) $data['clicks'] : 0;
361
362
        return $data;
363
    }
364
365
    /**
366
     * Make inactive banner images that has time out active_to date
367
     */
368
    public function setInactiveOnTimeOut() {
369
        return BannerImageQuery::create()
370
            ->filterByActive(1)
371
            ->where('BannerImage.ActiveTo < ?', time())
372
            ->update(['Active' => 0]);
373
    }
374
375
}