Completed
Push — master ( f69da3...1ada0c )
by Christopher
02:13
created

ActiveRecord::insertInternal()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 17
nc 3
nop 1
1
<?php
2
/**
3
 * @link      https://github.com/chrmorandi/yii2-ldap for the canonical source repository
4
 * @package   yii2-ldap
5
 * @author    Christopher Mota <[email protected]>
6
 * @license   MIT License - view the LICENSE file that was distributed with this source code.
7
 */
8
9
namespace chrmorandi\ldap;
10
11
use chrmorandi\ldap\ActiveQuery;
12
use chrmorandi\ldap\Connection;
13
use Exception;
14
use Yii;
15
use yii\db\BaseActiveRecord;
16
17
/**
18
 * ActiveRecord is the base class for classes representing relational data in terms of objects.
19
 *
20
 * This class implements the ActiveRecord pattern for the [ldap] protocol.
21
 *
22
 * For defining a record a subclass should at least implement the [[attributes()]] method to define
23
 * attributes or use some prepared traits for specific objects. A primary key can be defined via [[primaryKey()]] which defaults to `cn` if not specified.
24
 *
25
 * The following is an example model called `User`:
26
 *
27
 * ```php
28
 * class User extends \chrmorandi\ldap\ActiveRecord
29
 * {
30
 *     public function attributes()
31
 *     {
32
 *         return ['objectClass', 'cn', 'name'];
33
 *     }
34
 * }
35
 * ```
36
 * Or
37
 *
38
 * ```php
39
 * public function attributes() {
40
 *     return \chrmorandi\ldap\schemas\ADUser::getAttributes();
41
 * }
42
 * ```
43
 *
44
 * @since 1.0.0
45
 */
46
class ActiveRecord extends BaseActiveRecord
47
{    
0 ignored issues
show
Coding Style introduced by
The opening class brace should be on a newline by itself.
Loading history...
48
    /**
49
     * Returns the LDAP connection used by this AR class.
50
     *
51
     * @return Connection the LDAP connection used by this AR class.
52
     */
53
    public static function getDb()
54
    {
55
        return Yii::$app->get('ldap');
56
    }
57
    
58
    /**
59
     * @inheritdoc
60
     * @return ActiveQuery the newly created [[ActiveQuery]] instance.
61
     */
62
    public static function find()
63
    {
64
        return Yii::createObject(ActiveQuery::class, [get_called_class()]);
65
    }
66
67
    /**
68
     * Returns the primary key name(s) for this AR class.
69
     * This method should be overridden by child classes to define the primary key.
70
     *
71
     * @return string[] the primary keys of this record.
72
     */
73
    public static function primaryKey()
74
    {
75
        return ['dn'];
76
    }
77
    
78
    /**
79
     * Returns the list of attribute names.
80
     * You must override this method to define avaliable attributes.
81
     * @return array list of attribute names.
82
     */
83
    public function attributes()
84
    {
85
        throw new InvalidConfigException('The attributes() method of ldap ActiveRecord has to be implemented by child classes.');
86
    }
87
    
88
    /**
89
     * Inserts a row into the associated database table using the attribute values of this record.
90
     *
91
     * This method performs the following steps in order:
92
     *
93
     * 1. call [[beforeValidate()]] when `$runValidation` is true. If [[beforeValidate()]]
94
     *    returns `false`, the rest of the steps will be skipped;
95
     * 2. call [[afterValidate()]] when `$runValidation` is true. If validation
96
     *    failed, the rest of the steps will be skipped;
97
     * 3. call [[beforeSave()]]. If [[beforeSave()]] returns `false`,
98
     *    the rest of the steps will be skipped;
99
     * 4. insert the record into database. If this fails, it will skip the rest of the steps;
100
     * 5. call [[afterSave()]];
101
     *
102
     * In the above step 1, 2, 3 and 5, events [[EVENT_BEFORE_VALIDATE]],
103
     * [[EVENT_AFTER_VALIDATE]], [[EVENT_BEFORE_INSERT]], and [[EVENT_AFTER_INSERT]]
104
     * will be raised by the corresponding methods.
105
     *
106
     * Only the [[dirtyAttributes|changed attribute values]] will be inserted into database.
107
     *
108
     * If the table's primary key is auto-incremental and is null during insertion,
109
     * it will be populated with the actual value after insertion.
110
     *
111
     * For example, to insert a customer record:
112
     *
113
     * ```php
114
     * $customer = new Customer;
115
     * $customer->name = $name;
116
     * $customer->email = $email;
117
     * $customer->insert();
118
     * ```
119
     *
120
     * @param  boolean $runValidation whether to perform validation (calling [[validate()]])
121
     * before saving the record. Defaults to `true`. If the validation fails, the record
122
     * will not be saved to the database and this method will return `false`.
123
     * @param  string[]|null $attributes    list of attributes that need to be saved. Defaults to null, meaning all attributes that are loaded from DB will be saved. meaning all attributes that are loaded from DB will be saved.
124
     * meaning all attributes that are loaded from DB will be saved.
125
     * @return boolean whether the attributes are valid and the record is inserted successfully.
126
     * @throws Exception in case insert failed.
127
     */
128
    public function insert($runValidation = true, $attributes = null)
129
    {
130
        if ($runValidation && !$this->validate($attributes)) {
131
            Yii::info('Model not inserted due to validation error.', __METHOD__);
132
            return false;
133
        }
134
135
        return $this->insertInternal($attributes);
136
    }
137
    
138
    /**
139
     * Inserts an ActiveRecord into LDAP without.
140
     *
141
     * @param  string[]|null $attributes list of attributes that need to be saved. Defaults to null,
142
     * meaning all attributes that are loaded will be saved.
143
     * @return boolean whether the record is inserted successfully.
144
     */
145
    protected function insertInternal($attributes = null)
146
    {
147
        if (!$this->beforeSave(true)) {
148
            return false;
149
        }
150
        
151
        $primaryKey = static::primaryKey();
152
        $values = $this->getDirtyAttributes($attributes);
153
        $dn = $values[$primaryKey[0]];
154
        unset($values[$primaryKey[0]]);
155
        
156
        static::getDb()->open();
157
158
        if (static::getDb()->add($dn, $values) === false) {
159
            return false;
160
        }
161
        $this->setAttribute($primaryKey[0], $dn);
162
        $values[$primaryKey[0]] = $dn;
163
164
        $changedAttributes = array_fill_keys(array_keys($values), null);
165
        $this->setOldAttributes($values);
166
        $this->afterSave(true, $changedAttributes);
167
        
168
        static::getDb()->close();
169
170
        return true;
171
    }
172
    
173
    /**
174
     * @see update()
175
     * @param array $attributes attributes to update
176
     * @return integer number of rows updated
177
     * @throws StaleObjectException
178
     */
179
    protected function updateInternal($attributes = null)
180
    {
181
        if (!$this->beforeSave(false)) {
182
            return false;
183
        }
184
        $values = $this->getDirtyAttributes($attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 179 can also be of type array; however, yii\db\BaseActiveRecord::getDirtyAttributes() does only seem to accept array<integer,string>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
185
        if (empty($values)) {
186
            $this->afterSave(false, $values);
187
            return 0;
188
        }
189
190
        if(($condition = $this->getOldPrimaryKey(true)) !== $this->getPrimaryKey(true)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
191
            // TODO Change DN
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
192
//            static::getDb()->rename($condition, $newRdn, $newParent, true);
193
//            if (!$this->refresh()){
194
//                Yii::info('Model not refresh.', __METHOD__);
195
//                return false;
196
//            }
197
        }
198
        
199
        foreach ($values as $key => $value) {
200
            if($key == 'dn'){
201
                continue;
202
            }
203
            if(empty ($this->getOldAttribute($key)) && $value === ''){
204
                unset($values[$key]);
205
            } else if($value === ''){
206
                $attributes[] = ['attrib'  => $key, 'modtype' => LDAP_MODIFY_BATCH_REMOVE];
207
            } else if (empty ($this->getOldAttribute($key))) {
208
                $attributes[] = ['attrib'  => $key, 'modtype' => LDAP_MODIFY_BATCH_ADD, 'values' => [$value]];
209
            } else {
210
                $attributes[] = ['attrib'  => $key, 'modtype' => LDAP_MODIFY_BATCH_REPLACE, 'values' => [$value]];
211
            }
212
        }
213
        
214
        if (empty($attributes)) {
215
            $this->afterSave(false, $attributes);
0 ignored issues
show
Bug introduced by
It seems like $attributes defined by parameter $attributes on line 179 can also be of type null; however, yii\db\BaseActiveRecord::afterSave() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
216
            return 0;
217
        }
218
219
        // We do not check the return value of updateAll() because it's possible
220
        // that the UPDATE statement doesn't change anything and thus returns 0.
221
        $rows = static::updateAll($attributes, $condition);
222
223
//        $changedAttributes = [];
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
224
//        foreach ($values as $key => $value) {
225
//            $changedAttributes[$key] = empty($this->getOldAttributes($key)) ? $this->getOldAttributes($key) : null;
226
//            $this->setOldAttributes([$key=>$value]);
227
//        }
228
//        $this->afterSave(false, $changedAttributes);
229
230
        return $rows;
231
    }
232
    
233
    /**
234
     * Updates the whole table using the provided attribute values and conditions.
235
     * For example, to change the status to be 1 for all customers whose status is 2:
236
     *
237
     * ```php
238
     * Customer::updateAll(['status' => 1], 'status = 2');
239
     * ```
240
     *
241
     * @param array $attributes attribute values (name-value pairs) to be saved into the table
242
     * @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
243
     * Please refer to [[Query::where()]] on how to specify this parameter.
244
     * @return integer the number of rows updated
245
     */
246
    public static function updateAll($attributes, $condition = '')
247
    {
248
        if(is_array($condition)){
249
            $condition = $condition['dn'];
250
        }        
251
        
252
        static::getDb()->open();
253
        $teste = static::getDb()->modify($condition, $attributes);
0 ignored issues
show
Unused Code introduced by
$teste is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
254
        static::getDb()->close();
255
        
256
        return count($attributes);
257
    }
258
    
259
    /**
260
     * Deletes rows in the table using the provided conditions.
261
     * WARNING: If you do not specify any condition, this method will delete ALL rows in the ldap directory.
262
     *
263
     * For example, to delete all customers whose status is 3:
264
     *
265
     * ```php
266
     * Customer::deleteAll('status = 3');
267
     * ```
268
     *
269
     * @param  string|array $condition the conditions that will be put in the WHERE part of the DELETE SQL.
270
     * Please refer to [[Query::where()]] on how to specify this parameter.
271
     * @return integer the number of rows deleted
272
     */
273
    public static function deleteAll($condition = '')
274
    {
275
        $entries = (new Query())->select(self::primaryKey())->where($condition)->execute()->toArray();
276
        $count = 0;
277
        
278
        foreach ($entries as $entry) {
279
            $params = [
280
                $entry[self::primaryKey()]
281
            ];
282
            static::getDb()->execute('ldap_delete', $params);
0 ignored issues
show
Bug introduced by
The method execute() does not exist on chrmorandi\ldap\Connection. Did you maybe mean executeQuery()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
283
            $count++;
284
        }
285
        return $count;
286
    }
287
}
288