Passed
Push — master ( 173a0c...14edb3 )
by Vitaly
19:05 queued 09:05
created

Application::__async_edit()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 43
Code Lines 27

Duplication

Lines 10
Ratio 23.26 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 10
loc 43
rs 8.439
cc 6
eloc 27
nc 6
nop 1
1
<?php
2
namespace samsoncms\app\gallery;
3
4
use samson\activerecord\Field;
5
use samsoncms\api\CMS;
6
use samsoncms\api\Material;
7
use samsoncms\api\MaterialField;
8
use samsonphp\event\Event;
9
use samsoncms\app\gallery\tab\Gallery;
10
11
/**
12
 * SamsonCMS application for interacting with material gallery
13
 * @author [email protected]
14
 */
15
class Application extends \samsoncms\Application
16
{
17
    /** Application name */
18
    public $name = 'Галлерея';
19
20
    /** Hide application access from main menu */
21
    public $hide = true;
22
23
    /** @var string Entity class name */
24
    protected $entity = '\samson\activerecord\gallery';
25
26
    /** Identifier */
27
    protected $id = 'gallery';
28
29
    /** @var \samsonphp\fs\FileService File service pointer */
30
    protected $fs;
31
32
    /**
33
     * Initialize module
34
     * @param array $params Collection of parameters
35
     * @return bool True if success
36
     */
37
    public function init(array $params = array())
38
    {
39
        // TODO: Should be change to DI in future
40
        // Set pointer to file service
41
        $this->fs = & $this->system->module('fs');
42
43
        // Subscribe to material form created event for custom tab rendering
44
        Event::subscribe('samsoncms.material.form.created', array($this, 'tabBuilder'));
45
46
        // Subscribe to event - add gallery field additional field type
47
        Event::subscribe('cms_field.select_create', array($this, 'fieldSelectCreate'));
48
49
        return parent::init($params);
50
    }
51
52
    /**
53
     * Render all gallery additional fields as material form tabs
54
     * @param \samsoncms\app\material\form\Form $form Material form insctance
55
     */
56
    public function tabBuilder(\samsoncms\app\material\form\Form & $form)
57
    {
58
        // If we have related structures
59
        if (count($form->navigationIDs)) {
60
            // Get all gallery additional field for material form structures
61
            $galleryFields = $this->query->entity(\samsoncms\api\Field::class)
62
                ->where('Type', 9)
63
                ->join('structurefield')
64
                ->where('structurefield_StructureID', $form->navigationIDs)
65
                ->exec();
66
67
            // Create tab for each additional gallery field
68
            foreach ($galleryFields as $field) {
0 ignored issues
show
Bug introduced by
The expression $galleryFields of type boolean|array<integer,ob...k\orm\RecordInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
69
                $form->tabs[] = new Gallery($this, $this->query, $form->entity, $field);
70
            }
71
        }
72
    }
73
74
    /** Field select creation event handler */
75
    public function fieldSelectCreate(&$list)
76
    {
77
        $list[t('Галлерея', true)] = 9;
78
    }
79
80
    /**
81
     * Controller for deleting material image from gallery
82
     * @param string $imageId Gallery Image identifier
83
     * @return array Async response array
84
     */
85
    public function __async_delete($imageId, $materialFieldID = null)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_delete" is not in camel caps format
Loading history...
86
    {
87
        // Async response
88
        $result = array();
89
90
        /** @var \samson\activerecord\gallery $image */
91
        $image = null;
92
93
        // Find gallery record in DB
94
        if ($this->findAsyncEntityByID($imageId, $image, $result)) {
95
            if ($image->Path != '') {
96
                // Get image path
97
                $imagePath = $this->formImagePath($image->Path, $image->Src);
98
                // Physically remove file from server
99
                if ($this->imageExists($imagePath)) {
100
                    $this->fs->delete($imagePath);
101
                }
102
103
                // Delete thumbnails
104
                if (class_exists('\samson\scale\ScaleController', false)) {
105
                    /** @var \samson\scale\ScaleController $scale */
106
                    $scale = $this->system->module('scale');
107
108
                    foreach (array_keys($scale->thumnails_sizes) as $folder) {
109
                        // Form image path for scale module
110
                        $imageScalePath = $this->formImagePath($image->Path . $folder . '/', $image->Src);
111
                        if ($this->imageExists($imageScalePath)) {
112
                            $this->fs->delete($imageScalePath);
113
                        }
114
                    }
115
                }
116
            }
117
118
            // Remove record from DB
119
            $image->delete();
120
        }
121
122
        return $this->__async_update($materialFieldID);
123
    }
124
125
    /**
126
     * Controller for rendering gallery images list
127
     * @param int $materialFieldId Gallery identifier, represented as materialfield id
128
     * @return array Async response array
129
     */
130
    public function __async_update($materialFieldId)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_update" is not in camel caps format
Loading history...
131
    {
132
        return array('status' => true, 'html' => $this->getHTML($materialFieldId));
133
    }
134
135
	/**
136
     * Controller for getting quantity image in gallery.
137
     *
138
     * @param integer $materialFieldId identefier Table MaterialField
139
     * @return array Async response array with additional param count.
140
     */
141
    public function __async_getCount($materialFieldId)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_getCount" is not in camel caps format
Loading history...
142
    {
143
        // @var array $result Result of asynchronous controller
144
        $response = array('status' => 1);
145
        // Getting quantity from DB by param materialFieldId
146
        $response['count'] = $this->query
147
            ->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)
148
            ->where(MaterialField::F_PRIMARY, $materialFieldId)
149
            ->count();
150
151
        return $response;
152
    }
153
	
154
	/**
155
     *  Controller for update material image properties alt from gallery.
156
     *
157
     *  @param int $imageId Gallery image identifier
158
     *  @return array async response
159
     */
160
    public function __async_updateAlt($imageId)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_updateAlt" is not in camel caps format
Loading history...
161
    {
162
        // @var array $result Result of asynchronous controller
163
        $result = array('status' => false);
164
        // @var \samson\activerecord\gallery $image Image to insert into editor
165
        $image = null;
166
        //get data from ajax
167
        $data = json_decode(file_get_contents('php://input'), true);
168
        //set input value
169
        $value = trim($data['value']);
170
171
172
        // Getting first field image
173
        if ($this->query->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)
174
            ->where('PhotoID', $imageId)->first($image)) {
175
            // Update value alt
176
            $image->Description = $value;
0 ignored issues
show
Bug introduced by
Accessing Description on the interface samsonframework\orm\RecordInterface 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...
177
            // Save result in datebase
178
            $image->save();
179
            // Set success status
180
            $result['status'] = true;
181
            // Reduce number of characters to 25
182
            $result['description'] = utf8_limit_string($value, 25, '...');
183
            // Return result value
184
            $result['value'] = $value;
185
        }
186
187
        return $result;
188
    }
189
	
190
    /**
191
     * Controller for image upload
192
     * @param string $materialFieldId Gallery identifier, represented as materialfield id
193
     * @return array Async response array
194
     */
195
    public function __async_upload($materialFieldId)
0 ignored issues
show
Coding Style introduced by
__async_upload uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
Method name "Application::__async_upload" is not in camel caps format
Loading history...
196
    {
197
        $result = array('status' => false);
198
199
        /** @var \samsonphp\upload\Upload $upload Pointer to uploader object */
200
        $upload = null;
201
        // Verify extension image
202
        if ($this->verifyExtensionFile()) {
203
            // Uploading file to server and path current material identifier
204
            if (uploadFile($upload, array(), $materialFieldId)) {
205
                /** @var \samson\activerecord\materialfield $materialField MaterialField object to identify gallery */
206
                $materialField = null;
207
//            /** @var array $children List of related materials */
208
//            $children = null;
209
                // Check if participant has not uploaded remix yet
210
                if (
211
                $this->query->entity(MaterialField::ENTITY)
212
                    ->where('MaterialFieldID', $materialFieldId)
213
                    ->where('Active', 1)
214
                    ->first($materialField)
215
                ) {
216
                    // Create empty db record
217
                    $photo = new \samson\activerecord\gallery(false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a null|object<samsonframew...\orm\DatabaseInterface>.

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...
218
                    $photo->Name = $upload->realName();
0 ignored issues
show
Bug introduced by
The property Name does not seem to exist in samson\activerecord\gallery.

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...
219
                    $photo->Src = $upload->name();
0 ignored issues
show
Bug introduced by
The property Src does not seem to exist in samson\activerecord\gallery.

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...
220
                    $photo->Path = $upload->path();
0 ignored issues
show
Bug introduced by
The property Path does not seem to exist in samson\activerecord\gallery.

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...
221
                    $photo->materialFieldId = $materialField->id;
0 ignored issues
show
Bug introduced by
Accessing id on the interface samsonframework\orm\RecordInterface 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...
Bug introduced by
The property materialFieldId does not seem to exist in samson\activerecord\gallery.

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...
222
                    $photo->MaterialID = $materialField->MaterialID;
0 ignored issues
show
Bug introduced by
Accessing MaterialID on the interface samsonframework\orm\RecordInterface 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...
Bug introduced by
The property MaterialID does not seem to exist in samson\activerecord\gallery.

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...
223
                    $photo->size = $upload->size();
0 ignored issues
show
Bug introduced by
The property size does not seem to exist in samson\activerecord\gallery.

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...
224
                    $photo->Active = 1;
0 ignored issues
show
Bug introduced by
The property Active does not seem to exist in samson\activerecord\gallery.

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...
225
                    $photo->save();
226
227
228
                    // Call scale if it is loaded
229
                    if (class_exists('\samson\scale\ScaleController', false)) {
230
                        /** @var \samson\scale\ScaleController $scale */
231
                        $scale = $this->system->module('scale');
232
                        $scale->resize($upload->fullPath(), $upload->name(), $upload->uploadDir);
233
                    }
234
235
                    $result['status'] = true;
236
                }
237
            }
238
        } else {
239
            $errorText = "Файл ( " . urldecode($_SERVER['HTTP_X_FILE_NAME']) . " ) не является картинкой!";
240
            $result = array('status' => false, 'errorText' => $errorText);
241
        }
242
243
        return $result;
244
    }
245
246
    /**
247
     * method for verify extension file
248
     * @return boolean true - file is image, false - file not image
249
     * */
250
    private function verifyExtensionFile()
0 ignored issues
show
Coding Style introduced by
verifyExtensionFile uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
251
    {
252
        $supported_image = array(
253
            'gif',
254
            'jpg',
255
            'jpeg',
256
            'png'
257
        );
258
259
        $fileName = $_SERVER['HTTP_X_FILE_NAME'];
260
261
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
262
        if (in_array($ext, $supported_image)) {
263
            return true;
264
        }
265
        return false;
266
    }
267
268
    /**
269
     * Function to save image priority
270
     * @return array Async response array
271
     */
272
    public function __async_priority()
0 ignored issues
show
Coding Style introduced by
__async_priority uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
Method name "Application::__async_priority" is not in camel caps format
Loading history...
273
    {
274
        $result = array('status' => true);
275
276
        // If we have changed priority of images
277
        if (isset($_POST['ids'])) {
278
            // For each received image id
279
            for ($i = 0; $i < count($_POST['ids']); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
280
                /** @var \samson\activerecord\gallery $photo Variable to store image info */
281
                $photo = null;
282
                // If we have such image in database
283
                if ($this->query->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)->where('PhotoID', $_POST['ids'][$i])->first($photo)) {
284
                    // Reset it's priority and save it
285
                    $photo->priority = $i;
0 ignored issues
show
Bug introduced by
Accessing priority on the interface samsonframework\orm\RecordInterface 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...
286
                    $photo->save();
287
                } else {
288
                    $result['status'] = false;
289
                    $result['message'] = 'Can not find images with specified ids!';
290
                }
291
            }
292
        } else {
293
            $result['status'] = false;
294
            $result['message'] = 'There are no images to sort!';
295
        }
296
        return $result;
297
    }
298
299
    /**
300
     * Asynchronous function to get image editor
301
     * @param int $imageId Image identifier to insert into editor
302
     * @return array Result array
303
     */
304
    public function __async_show_edit($imageId)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_show_edit" is not in camel caps format
Loading history...
305
    {
306
        /** @var array $result Result of asynchronous controller */
307
        $result = array('status' => false);
308
        /** @var \samson\activerecord\gallery $image Image to insert into editor */
309
        $image = null;
310
        if ($this->query->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)->where('PhotoID', $imageId)->first($image)) {
311
312
            /** @var string $path Path to image */
313
            $path = $this->formImagePath($image->Path, $image->Src);
0 ignored issues
show
Bug introduced by
Accessing Path on the interface samsonframework\orm\RecordInterface 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...
Bug introduced by
Accessing Src on the interface samsonframework\orm\RecordInterface 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...
314
315
            // If there is image for this path
316
            if ($this->imageExists($path)) {
317
                $result['status'] = true;
318
                $result['html'] = $this->view('editor/index')
319
                    ->set($image, 'image')
320
                    ->set($path, 'path')
321
                    ->output();
322
            }
323
        }
324
        return $result;
325
    }
326
327
    /**
328
     * Applies all changes with the image and save it
329
     * @param int $imageId Edit image identifier
330
     * @return array
331
     */
332
    public function __async_edit($imageId)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_edit" is not in camel caps format
Loading history...
333
    {
334
        /** @var array $result Result of asynchronous controller */
335
        $result = array('status' => false);
336
        /** @var \samson\activerecord\gallery $image Image to insert into editor */
337
        $image = null;
338
        /** @var resource $imageResource Copy of edit image */
339
        $imageResource = null;
340
        /** @var resource $croppedImage Resource of cropped image */
341
        $croppedImage = null;
342
343
        // If there is such image in database
344
        if ($this->query->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)->where('PhotoID', $imageId)->first($image)) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
345
346
            // Form proper path
347
            $path = $this->formImagePath($image->Path, $image->Src);
0 ignored issues
show
Bug introduced by
Accessing Path on the interface samsonframework\orm\RecordInterface 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...
Bug introduced by
Accessing Src on the interface samsonframework\orm\RecordInterface 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...
348
349
            // Check image extension
350
            switch (pathinfo($path, PATHINFO_EXTENSION)) {
351
                case 'jpeg':
352
                case 'jpg':
353
                    $imageResource = imagecreatefromjpeg($path);
354
                    $croppedImage = $this->cropImage($imageResource);
0 ignored issues
show
Documentation Bug introduced by
The method cropImage does not exist on object<samsoncms\app\gallery\Application>? 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...
355
                    $result['status'] = imagejpeg($croppedImage, $path);
356
                    break;
357 View Code Duplication
                case 'png':
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...
358
                    $imageResource = imagecreatefrompng($path);
359
                    $croppedImage = $this->cropTransparentImage($imageResource);
0 ignored issues
show
Documentation Bug introduced by
The method cropTransparentImage does not exist on object<samsoncms\app\gallery\Application>? 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...
360
                    $result['status'] = imagepng($croppedImage, $path);
361
                    break;
362 View Code Duplication
                case 'gif':
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...
363
                    $imageResource = imagecreatefromgif($path);
364
                    $croppedImage = $this->cropTransparentImage($imageResource);
0 ignored issues
show
Documentation Bug introduced by
The method cropTransparentImage does not exist on object<samsoncms\app\gallery\Application>? 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...
365
                    $result['status'] = imagegif($croppedImage, $path);
366
                    break;
367
            }
368
369
            // delete temporary images
370
            imagedestroy($croppedImage);
371
            imagedestroy($imageResource);
372
        }
373
        return $result;
374
    }
375
376
    /**
377
     * Render gallery images list
378
     * @param string $materialFieldId Material identifier
379
     * @return string html representation of image list
380
     */
381
    public function getHTML($materialFieldId)
382
    {
383
        // Get all material images
384
        $items_html = '';
385
        /** @var array $images List of gallery images */
386
        $images = null;
387
        // there are gallery images
388
        if ($this->query->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)->where('materialFieldId', $materialFieldId)->orderBy('priority')->exec($images)) {
389
            /** @var \samson\cms\CMSGallery $image */
390
            foreach ($images as $image) {
0 ignored issues
show
Bug introduced by
The expression $images of type null|array<integer,objec...k\orm\RecordInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
391
                // Get image size string
392
                $size = ', ';
393
                // Get image path
394
                $path = $this->formImagePath($image->Path, $image->Src);
395
396
                // if file doesn't exist
397
                if (!$this->imageExists($path)) {
398
                    $path = \samson\resourcer\ResourceRouter::url('www/img/no-img.png', $this);
399
                }
400
401
                // set image size string representation, if it is not 0
402
                $size = ($image->size == 0) ? '' : $size . $this->humanFileSize($image->size);
403
404
                // Render gallery image tumb
405
                $items_html .= $this->view('tumbs/item')
406
                    ->set($image, 'image')
407
                    ->set(utf8_limit_string($image->Description, 25, '...'), 'description')
408
                    ->set(utf8_limit_string($image->Name, 18, '...'), 'name')
409
                    ->set($path, 'imgpath')
410
                    ->set($size, 'size')
411
                    ->set($materialFieldId, 'material_id')
412
                    ->output();
413
            }
414
        }
415
416
        // Render content into inner content html
417
        return $this->view('tumbs/index')
418
            ->set($items_html, 'images')
419
            ->set($materialFieldId, 'material_id')
420
            ->output();
421
    }
422
423
    /**
424
     * Function to form image size
425
     * @param int $bytes Bytes count
426
     * @param int $decimals Decimal part of number(count of numbers)
427
     * @return string Generated image size
428
     */
429
    public function humanFileSize($bytes, $decimals = 2)
430
    {
431
        /** @var string $sizeLetters Size shortcuts */
432
        $sizeLetters = 'BKBMBGBTBPB';
433
        $factor = (int)(floor((strlen($bytes) - 1) / 3));
434
        $sizeLetter = ($factor <= 0) ? substr($sizeLetters, 0, 1) : substr($sizeLetters, $factor * 2 - 1, 2);
435
        return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . $sizeLetter;
436
    }
437
438
    /**
439
     * Checks if image exists, supports old database structure
440
     * @param string $imagePath Path to image(Full or not)
441
     * @param string $imageSrc Image name, if it wasn't in $imagePath
442
     * @return bool
443
     */
444
    private function imageExists($imagePath, $imageSrc = null)
445
    {
446
        // If image name is sewhere parameter
447
        if (isset($imageSrc)) {
448
            // Form path to the image
449
            $imageFullPath = $this->formImagePath($imagePath, $imageSrc);
450
        } else {
451
            // Path was already set
452
            $imageFullPath = $imagePath;
453
        }
454
455
        // Call file service existence method
456
        return $this->fs->exists($imageFullPath);
457
    }
458
459
    /**
460
     * Function to form image path correctly, also supports old database structure
461
     * @param string $imagePath Path to the image
462
     * @param string $imageSrc Image name
463
     * @return string Full path to image
464
     */
465
    private function formImagePath($imagePath, $imageSrc)
466
    {
467
        // Get old-way image path, remove full path to check file
468
        if (empty($imagePath)) {
469
            $path = $imageSrc;
470
        } else { // Use new CORRECT way
471
            $path = $imagePath . $imageSrc;
472
        }
473
474
        // form relative path to the image
475
        $dir = quotemeta(__SAMSON_BASE__);
476
        // TODO: WTF? Why do we need this, need comments!!!
477
        if (strpos($path, 'http://') === false) {
478
            if ($dir == '/') {
479
                return substr($path, 1);
480
            } else {
481
                return preg_replace('/' . addcslashes($dir, '/') . '/', '', $path);
482
            }
483
        }
484
485
        return $path;
486
    }
487
}
488