Test Failed
Push — master ( 792760...743be5 )
by Julien
04:27
created

Position::beforeValidation()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 7
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 11
rs 9.6111
1
<?php
2
3
/**
4
 * This file is part of the Zemit Framework.
5
 *
6
 * (c) Zemit Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zemit\Mvc\Model\Behavior;
13
14
use Phalcon\Db\RawValue;
15
use Phalcon\Mvc\Model\Behavior;
16
use Phalcon\Mvc\ModelInterface;
17
use Phalcon\Text;
18
use Zemit\Mvc\Model;
19
20
class Position extends Behavior
21
{
22
    use ProgressTrait;
23
    use SkippableTrait;
24
    
25
    public bool $progress = false;
26
    
27
    public function setField(string $field): void
28
    {
29
        $this->options['field'] = $field;
30
    }
31
    
32
    public function getField(): string
33
    {
34
        return $this->options['field'];
35
    }
36
    
37
    public function setRawSql(bool $rawSql): void
38
    {
39
        $this->options['rawSql'] = $rawSql;
40
    }
41
    
42
    public function getRawSql(): bool
43
    {
44
        return $this->options['rawSql'];
45
    }
46
    
47
    public function hasProperty(ModelInterface $model, string $field): bool
48
    {
49
        return property_exists($model, $field);
50
    }
51
    
52
    public function __construct(array $options = [])
53
    {
54
        parent::__construct($options);
55
        $this->setField($options['field'] ?? 'position');
56
        $this->setRawSql($options['rawSql'] ?? true);
57
    }
58
    
59
    /**
60
     * Set the default position field value before validation
61
     * Shift position+1 and position-1 to other records after save
62
     */
63
    public function notify(string $type, ModelInterface $model)
64
    {
65
        if (!$this->isEnabled()) {
66
            return;
67
        }
68
        
69
        $field = $this->getField();
70
        $rawSql = $this->getRawSql();
0 ignored issues
show
Unused Code introduced by
The assignment to $rawSql is dead and can be removed.
Loading history...
71
        
72
        // skip if the current model doesn't have the position property defined
73
        if (!$this->hasProperty($model, $field)) {
74
            return;
75
        }
76
        
77
        switch ($type) {
78
            case 'beforeValidation':
79
                $this->beforeValidation($model, $field);
80
                break;
81
            
82
            case 'afterSave':
83
//                $this->afterSave($model, $field, $rawSql);
84
                break;
85
        }
86
        
87
        return true;
88
    }
89
    
90
    /**
91
     * Force the current position to max(position)+1 if it's empty
92
     * will only happen if the position field is present on the current model
93
     */
94
    public function beforeValidation(ModelInterface $model, string $field): void
95
    {
96
        if (property_exists($model, $field)) {
97
            $positionValue = $model->readAttribute($field);
0 ignored issues
show
Bug introduced by
The method readAttribute() does not exist on Phalcon\Mvc\ModelInterface. It seems like you code against a sub-type of Phalcon\Mvc\ModelInterface such as Phalcon\Mvc\Model or Zemit\Models\Setting or Zemit\Models\Category or Zemit\Models\Audit or Zemit\Models\UserGroup or Zemit\Models\User or Zemit\Models\Field or Zemit\Models\Page or Zemit\Models\Log or Zemit\Models\File or Zemit\Models\Role or Zemit\Models\GroupRole or Zemit\Models\Template or Zemit\Models\AuditDetail or Zemit\Models\UserType or Zemit\Models\Post or Zemit\Models\PostCategory or Zemit\Models\Session or Zemit\Models\TranslateField or Zemit\Models\GroupType or Zemit\Models\Translate or Zemit\Models\Email or Zemit\Models\Data or Zemit\Models\Group or Zemit\Models\Lang or Zemit\Models\EmailFile or Zemit\Models\TranslateTable or Zemit\Models\SiteLang or Zemit\Models\UserRole or Zemit\Models\Flag or Zemit\Models\Menu or Zemit\Models\Site or Zemit\Models\Type or Zemit\Models\Channel or Zemit\Models\Meta. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

97
            /** @scrutinizer ignore-call */ 
98
            $positionValue = $model->readAttribute($field);
Loading history...
98
            if (is_null($positionValue)) {
99
                
100
                // if position field is empty, force current max(position)+1
101
                $lastPosition = $model::findFirst(['order' => $field . ' DESC']);
102
                if ($lastPosition && assert($lastPosition instanceof $model)) {
103
                    $position = (int)$lastPosition->readAttribute($field);
104
                    $model->writeAttribute($field, $position + 1);
0 ignored issues
show
Bug introduced by
The method writeAttribute() does not exist on Phalcon\Mvc\ModelInterface. It seems like you code against a sub-type of Phalcon\Mvc\ModelInterface such as Phalcon\Mvc\Model or Zemit\Models\Setting or Zemit\Models\Category or Zemit\Models\Audit or Zemit\Models\UserGroup or Zemit\Models\User or Zemit\Models\Field or Zemit\Models\Page or Zemit\Models\Log or Zemit\Models\File or Zemit\Models\Role or Zemit\Models\GroupRole or Zemit\Models\Template or Zemit\Models\AuditDetail or Zemit\Models\UserType or Zemit\Models\Post or Zemit\Models\PostCategory or Zemit\Models\Session or Zemit\Models\TranslateField or Zemit\Models\GroupType or Zemit\Models\Translate or Zemit\Models\Email or Zemit\Models\Data or Zemit\Models\Group or Zemit\Models\Lang or Zemit\Models\EmailFile or Zemit\Models\TranslateTable or Zemit\Models\SiteLang or Zemit\Models\UserRole or Zemit\Models\Flag or Zemit\Models\Menu or Zemit\Models\Site or Zemit\Models\Type or Zemit\Models\Channel or Zemit\Models\Meta. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

104
                    $model->/** @scrutinizer ignore-call */ 
105
                            writeAttribute($field, $position + 1);
Loading history...
105
                }
106
            }
107
        }
108
    }
109
    
110
    // @todo fix combined primary keys
111
    public function afterSave(ModelInterface $model, string $field, bool $rawSql): void
112
    {
113
        if (!$this->getProgress() && $model->hasSnapshotData() && $model->hasUpdated($field)) {
0 ignored issues
show
Bug introduced by
The method hasUpdated() does not exist on Phalcon\Mvc\ModelInterface. It seems like you code against a sub-type of Phalcon\Mvc\ModelInterface such as Phalcon\Mvc\Model or Zemit\Models\Setting or Zemit\Models\Category or Zemit\Models\Audit or Zemit\Models\UserGroup or Zemit\Models\User or Zemit\Models\Field or Zemit\Models\Page or Zemit\Models\Log or Zemit\Models\File or Zemit\Models\Role or Zemit\Models\GroupRole or Zemit\Models\Template or Zemit\Models\AuditDetail or Zemit\Models\UserType or Zemit\Models\Post or Zemit\Models\PostCategory or Zemit\Models\Session or Zemit\Models\TranslateField or Zemit\Models\GroupType or Zemit\Models\Translate or Zemit\Models\Email or Zemit\Models\Data or Zemit\Models\Group or Zemit\Models\Lang or Zemit\Models\EmailFile or Zemit\Models\TranslateTable or Zemit\Models\SiteLang or Zemit\Models\UserRole or Zemit\Models\Flag or Zemit\Models\Menu or Zemit\Models\Site or Zemit\Models\Type or Zemit\Models\Channel or Zemit\Models\Meta. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
        if (!$this->getProgress() && $model->hasSnapshotData() && $model->/** @scrutinizer ignore-call */ hasUpdated($field)) {
Loading history...
Bug introduced by
The method hasSnapshotData() does not exist on Phalcon\Mvc\ModelInterface. It seems like you code against a sub-type of Phalcon\Mvc\ModelInterface such as Phalcon\Mvc\Model or Zemit\Models\Setting or Zemit\Models\Category or Zemit\Models\Audit or Zemit\Models\UserGroup or Zemit\Models\User or Zemit\Models\Field or Zemit\Models\Page or Zemit\Models\Log or Zemit\Models\File or Zemit\Models\Role or Zemit\Models\GroupRole or Zemit\Models\Template or Zemit\Models\AuditDetail or Zemit\Models\UserType or Zemit\Models\Post or Zemit\Models\PostCategory or Zemit\Models\Session or Zemit\Models\TranslateField or Zemit\Models\GroupType or Zemit\Models\Translate or Zemit\Models\Email or Zemit\Models\Data or Zemit\Models\Group or Zemit\Models\Lang or Zemit\Models\EmailFile or Zemit\Models\TranslateTable or Zemit\Models\SiteLang or Zemit\Models\UserRole or Zemit\Models\Flag or Zemit\Models\Menu or Zemit\Models\Site or Zemit\Models\Type or Zemit\Models\Channel or Zemit\Models\Meta. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
        if (!$this->getProgress() && $model->/** @scrutinizer ignore-call */ hasSnapshotData() && $model->hasUpdated($field)) {
Loading history...
114
            self::staticStart();
115
            
116
            $snapshot = $model->getOldSnapshotData() ?: $model->getSnapshotData();
0 ignored issues
show
Bug introduced by
The method getOldSnapshotData() does not exist on Phalcon\Mvc\ModelInterface. Did you maybe mean setSnapshotData()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
            $snapshot = $model->/** @scrutinizer ignore-call */ getOldSnapshotData() ?: $model->getSnapshotData();

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

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

Loading history...
Bug introduced by
The method getSnapshotData() does not exist on Phalcon\Mvc\ModelInterface. It seems like you code against a sub-type of Phalcon\Mvc\ModelInterface such as Phalcon\Mvc\Model or Zemit\Models\Setting or Zemit\Models\Category or Zemit\Models\Audit or Zemit\Models\UserGroup or Zemit\Models\User or Zemit\Models\Field or Zemit\Models\Page or Zemit\Models\Log or Zemit\Models\File or Zemit\Models\Role or Zemit\Models\GroupRole or Zemit\Models\Template or Zemit\Models\AuditDetail or Zemit\Models\UserType or Zemit\Models\Post or Zemit\Models\PostCategory or Zemit\Models\Session or Zemit\Models\TranslateField or Zemit\Models\GroupType or Zemit\Models\Translate or Zemit\Models\Email or Zemit\Models\Data or Zemit\Models\Group or Zemit\Models\Lang or Zemit\Models\EmailFile or Zemit\Models\TranslateTable or Zemit\Models\SiteLang or Zemit\Models\UserRole or Zemit\Models\Flag or Zemit\Models\Menu or Zemit\Models\Site or Zemit\Models\Type or Zemit\Models\Channel or Zemit\Models\Meta. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
            $snapshot = $model->getOldSnapshotData() ?: $model->/** @scrutinizer ignore-call */ getSnapshotData();
Loading history...
117
            $modelPosition = $model->readAttribute($field);
118
            $modelPrimaryKeys = $model->getPrimaryKeysValues();
0 ignored issues
show
Bug introduced by
The method getPrimaryKeysValues() does not exist on Phalcon\Mvc\ModelInterface. It seems like you code against a sub-type of Phalcon\Mvc\ModelInterface such as Phalcon\Mvc\Model or Zemit\Models\Setting or Zemit\Models\Category or Zemit\Models\Audit or Zemit\Models\UserGroup or Zemit\Models\User or Zemit\Models\Field or Zemit\Models\Page or Zemit\Models\Log or Zemit\Models\File or Zemit\Models\Role or Zemit\Models\GroupRole or Zemit\Models\Template or Zemit\Models\AuditDetail or Zemit\Models\UserType or Zemit\Models\Post or Zemit\Models\PostCategory or Zemit\Models\Session or Zemit\Models\TranslateField or Zemit\Models\GroupType or Zemit\Models\Translate or Zemit\Models\Email or Zemit\Models\Data or Zemit\Models\Group or Zemit\Models\Lang or Zemit\Models\EmailFile or Zemit\Models\TranslateTable or Zemit\Models\SiteLang or Zemit\Models\UserRole or Zemit\Models\Flag or Zemit\Models\Menu or Zemit\Models\Site or Zemit\Models\Type or Zemit\Models\Channel or Zemit\Models\Meta. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
            /** @scrutinizer ignore-call */ 
119
            $modelPrimaryKeys = $model->getPrimaryKeysValues();
Loading history...
119
            
120
            if (!($modelPosition instanceof RawValue)) {
121
                $uField = Text::uncamelize($field); // @todo use columnMap
122
                $updatePositionQuery = null;
123
                
124
                if ($snapshot[$field] > $modelPosition) {
125
                    $updatePositionQuery = $rawSql
126
                        ? 'UPDATE `' . $model->getSource() . '` SET `' . $uField . '` = `' . $uField . '`+1 WHERE `' . $uField . '` >= :position and `' . $uField . '` < :oldPosition and `' . $idField . '` <> :id'
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $idField seems to be never defined.
Loading history...
127
                        : 'UPDATE [' . get_class($model) . '] SET [' . $field . '] = [' . $field . ']+1 WHERE [' . $field . '] >= ?1 and [' . $field . '] < ?2 and [' . $idField . '] <> ?0';
128
                }
129
                elseif ($snapshot[$field] < $modelPosition) {
130
                    $updatePositionQuery = $rawSql
131
                        ? 'UPDATE `' . $model->getSource() . '` SET `' . $uField . '` = `' . $uField . '`-1 WHERE `' . $uField . '` > :oldPosition and `' . $uField . '` <= :position and `' . $idField . '` <> :id'
132
                        : 'UPDATE [' . get_class($model) . '] SET [' . $field . '] = [' . $field . ']-1 WHERE [' . $field . '] > ?2 and [' . $field . '] <= ?1 and [' . $idField . '] <> ?0';
133
                }
134
                
135
                if (!empty($updatePositionQuery)) {
136
                    if ($rawSql) {
137
                        $model->getWriteConnection()->query($updatePositionQuery, [
138
                            'primaryKeys' => $modelPrimaryKeys,
139
                            'position' => $modelPosition,
140
                            'oldPosition' => $snapshot[$field],
141
                        ]);
142
                    }
143
                    else {
144
                        $model->getModelsManager()->executeQuery($updatePositionQuery, [$modelId, $modelPosition, $snapshot[$field]]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $modelId does not exist. Did you maybe mean $model?
Loading history...
Bug introduced by
The method getModelsManager() does not exist on Phalcon\Mvc\ModelInterface. Did you maybe mean getModelsMetaData()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

144
                        $model->/** @scrutinizer ignore-call */ 
145
                                getModelsManager()->executeQuery($updatePositionQuery, [$modelId, $modelPosition, $snapshot[$field]]);

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

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

Loading history...
145
                    }
146
                }
147
            }
148
            
149
            self::staticStop();
150
        }
151
    }
152
}
153