Completed
Push — master ( 1586bf...4ce22d )
by Jean
02:08
created

ChainableArray_Utils_Trait::isAssoc()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace JClaveau\Arrays;
3
4
/**
5
 * Custom functions that can be used on arrays.
6
 */
7
trait ChainableArray_Utils_Trait
8
{
9
    /**
10
     * Same as $this->groupByTransformed() without the transformer to
11
     * improve the readability in some cases.
12
     *
13
     * @param  callable $indexGenerator   Can return a scalar or an array.
14
     *         Multiple indexes allow to add a row to multiple groups.
15
     * @param  callable $conflictResolver
16
     *
17
     * @throws Missing conflict resolver
18
     *
19
     * @return array The array containing the grouped rows.
20
     */
21
    public function groupBy( callable $indexGenerator, callable $conflictResolver=null )
22
    {
23
        // todo : this doesn't work
24
        // return $this->groupByTransformed($indexGenerator, null, $conflictResolver);
25
26
        $out = [];
27
        foreach ($this->data as $key => $row) {
28
29
            if (!$row)
30
                continue;
31
32
            $newIndexes     = call_user_func($indexGenerator, $key, $row);
33
            if (!is_array($newIndexes))
34
                $newIndexes = [$newIndexes];
35
36
            foreach ($newIndexes as $newIndex) {
37
                if (!isset($out[$newIndex])) {
38
                    $out[$newIndex] = $row;
39
                }
40
                else {
41
                    if ($conflictResolver === null) {
42
                        self::throwUsageException(
43
                            "A 'group by' provoking a conflict"
44
                            ." has no conflict resolver defined:\n"
45
                            ." + key: ".$key."\n"
46
                            ." + existing: ".var_export($out[$newIndex], true)."\n"
47
                            ." + conflict: ".var_export($row, true)."\n"
48
                        );
49
                    }
50
51
                    $out[$newIndex] = call_user_func(
52
                        $conflictResolver,
53
                        $newIndex,
54
                        $out[$newIndex],
55
                        $row
56
                    );
57
                }
58
            }
59
        }
60
61
        return $this->returnConstant($out);
0 ignored issues
show
Bug introduced by
It seems like returnConstant() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

61
        return $this->/** @scrutinizer ignore-call */ returnConstant($out);
Loading history...
62
    }
63
64
    /**
65
     * Group rows in arrays indexed by the index generated by $indexGenerator
66
     *
67
     * @param  callable $indexGenerator   Can return a scalar or an array.
68
     *         Multiple indexes allow to add a row to multiple groups.
69
     *
70
     * @return array The array containing the grouped rows.
71
     */
72
    public function groupInArrays( callable $indexGenerator )
73
    {
74
        $out = [];
75
        foreach ($this->data as $key => $row) {
76
77
            if (!$row)
78
                continue;
79
80
            $new_keys = call_user_func($indexGenerator, $row, $key);
81
            if (!is_array($new_keys))
82
                $new_keys = [$new_keys];
83
84
            foreach ($new_keys as $new_key) {
85
                if (!isset($out[ $new_key ])) {
86
                    $out[ $new_key ] = [
87
                        $key => $row
88
                    ];
89
                }
90
                else {
91
                    $out[ $new_key ][ $key ] = $row;
92
                }
93
            }
94
        }
95
96
        return $this->returnConstant($out);
97
    }
98
99
    /**
100
     * @deprecated Arrays::mergeRecursiveCustom
101
     */
102
    public static function mergeRecursiveCustom(
103
        array $existing_row,
104
        array $conflict_row,
105
        callable $merge_resolver=null,
106
        $max_depth=null
107
    ){
108
        return Arrays::mergePreservingDistincts(
109
            $existing_row,
110
            $conflict_row,
111
            $merge_resolver,
0 ignored issues
show
Unused Code introduced by
The call to JClaveau\Arrays\Arrays::mergePreservingDistincts() has too many arguments starting with $merge_resolver. ( Ignorable by Annotation )

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

111
        return Arrays::/** @scrutinizer ignore-call */ mergePreservingDistincts(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
112
            $max_depth
113
        );
114
    }
115
116
    /**
117
     * @deprecated Arrays::mergePreservingDistincts()
118
     */
119
    public static function mergePreservingDistincts(
120
        array $existing_row,
121
        array $conflict_row
122
    ) {
123
        return Arrays::keepUniqueColumnValues($existing_row, $conflict_row);
124
    }
125
126
    /**
127
     * @deprecated Arrays::mergePreservingDistincts()
128
     */
129
    public static function keepUniqueColumnValues(array $row, array $excluded_columns=[])
130
    {
131
        return Arrays::keepUniqueColumnValues($row, $excluded_columns);
132
    }
133
134
    /**
135
     * Parses an array and group it rows by index. This index is generated
136
     * by the first parameter.
137
     * The row corresponding to the new index can be different from the
138
     * grouped ones so the second parameter allows us to transform them.
139
     * Finally, the third parameter is used to resolve the conflict e.g.
140
     * when two rows generate the same index.
141
     *
142
     * @paramb callable $indexGenerator
143
     * @paramb callable $rowTransformer
144
     * @paramb callable $conflictResolver
145
     *
146
     * @return array The array containing the grouped rows.
147
     */
148
    public function groupByTransformed(
149
        callable $indexGenerator,
150
        callable $rowTransformer,      // todo check this behavior
151
        callable $conflictResolver )
152
    {
153
        // The goal here is to remove the second parameter has it makes the
154
        // grouping process too complicated
155
        // if (!$conflictResolver) {
156
            // $conflictResolver = $rowTransformer;
157
            // $rowTransformer   = null;
158
        // }
159
160
        $out = [];
161
        foreach ($this->data as $key => $row) {
162
163
            if (!$row)
164
                continue;
165
166
            $newIndex       = call_user_func($indexGenerator, $key, $row);
167
168
            $transformedRow = $rowTransformer
169
                            ? call_user_func($rowTransformer, $row)
170
                            : $row;
171
172
            if (!isset($out[$newIndex])) {
173
                $out[$newIndex] = $transformedRow;
174
            }
175
            else {
176
                $out[$newIndex] = call_user_func(
177
                    $conflictResolver,
178
                    $newIndex,
179
                    $out[$newIndex],
180
                    $transformedRow,
181
                    $row
182
                );
183
            }
184
        }
185
186
        return $this->returnConstant($out);
187
    }
188
189
    /**
190
     * Merge a table into another one
191
     *
192
     * @param static $otherTable       The table to merge into
193
     * @param callable     $conflictResolver Defines what to do if two
194
     *                                       rows have the same index.
195
     * @return static
196
     */
197
    public function mergeWith( $otherTable, callable $conflictResolver=null )
198
    {
199
        if (is_array($otherTable))
0 ignored issues
show
introduced by
The condition is_array($otherTable) is always false.
Loading history...
200
            $otherTable = new static($otherTable);
201
202
        if (!$otherTable instanceof static) {
0 ignored issues
show
introduced by
$otherTable is always a sub-type of static.
Loading history...
203
            self::throwUsageException(
204
                '$otherTable must be an array or an instance of '.static::class.' instead of: '
205
                .var_export($otherTable, true)
206
            );
207
        }
208
209
        $out = $this->data;
210
        foreach ($otherTable->getArray() as $key => $row) {
0 ignored issues
show
Bug introduced by
It seems like getArray() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

210
        foreach ($otherTable->/** @scrutinizer ignore-call */ getArray() as $key => $row) {
Loading history...
211
212
            if (!isset($out[$key])) {
213
                $out[$key] = $row;
214
            }
215
            else {
216
                if ($conflictResolver === null)
217
                    self::throwUsageException('No conflict resolver for a merge provoking one');
218
219
                $arguments = [
220
                    &$key,
221
                    $out[$key],
222
                    $row
223
                ];
224
225
                $out[$key] = call_user_func_array(
226
                    $conflictResolver,
227
                    $arguments
228
                );
229
            }
230
        }
231
232
        return $this->returnConstant($out);
233
    }
234
235
    /**
236
     * Merge the table $otherTable into the current table.
237
     * (same as self::mergeWith with the other table as $this)
238
     * @return static
239
     */
240
    public function mergeIn( $otherTable, callable $conflictResolver=null )
241
    {
242
        $otherTable->mergeWith($this, $conflictResolver);
243
        return $this;
244
    }
245
246
    /**
247
     * The same as self::mergeWith with an array of tables.
248
     *
249
     * @param array $othersTable array of HelperTable
250
     * @param func  $conflictResolver callback resolver
0 ignored issues
show
Bug introduced by
The type JClaveau\Arrays\func was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
251
     */
252
    public function mergeSeveralWith(array $othersTable, callable $conflictResolver = null)
253
    {
254
        foreach ($othersTable as $otherTable) {
255
            $this->mergeWith($otherTable, $conflictResolver);
256
        }
257
258
        return $this;
259
    }
260
261
    /**
262
     *
263
     */
264
    public function each(callable $rowTransformer)
265
    {
266
        $out  = [];
267
        foreach ($this->data as $key => $row) {
268
            $out[$key] = call_user_func_array(
269
                $rowTransformer,
270
                [$row, &$key, $this->data]
271
            );
272
        }
273
274
        return $this->returnConstant($out);
275
    }
276
277
    /**
278
     * Rename a column on every row.
279
     *
280
     * @todo remove this method and force the usage of $this->renameColumns()?
281
     * @deprecated use $this->renameColumns(Array) instead]
282
     *
283
     */
284
    public function renameColumn($old_name, $new_name)
285
    {
286
        return $this->renameColumns([$old_name => $new_name]);
287
    }
288
289
    /**
290
     * Rename a column on every row.
291
     *
292
     * @return static
293
     */
294
    public function renameColumns(array $old_to_new_names)
295
    {
296
        $out  = [];
297
        foreach ($this->data as $key => $row) {
298
            try {
299
                foreach ($old_to_new_names as $old_name => $new_name) {
300
                    $row[$new_name] = $row[$old_name];
301
                    unset($row[$old_name]);
302
                }
303
            }
304
            catch (\Exception $e) {
305
                self::throwUsageException( $e->getMessage() );
306
            }
307
308
            $out[$key] = $row;
309
        }
310
311
        return $this->returnConstant($out);
312
    }
313
314
    /**
315
     * Limits the size of the array.
316
     *
317
     * @param  int         $max
318
     * @return Heper_Table $this
0 ignored issues
show
Bug introduced by
The type JClaveau\Arrays\Heper_Table was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
319
     *
320
     * @todo implement other parameters for this function like in SQL
321
     */
322
    public function limit()
323
    {
324
        $arguments = func_get_args();
325
        if (count($arguments) == 1 && is_numeric($arguments[0]))
326
            $max = $arguments[0];
327
        else
328
            self::throwUsageException("Bad arguments type and count for limit()");
329
330
        $out   = [];
331
        $count = 0;
332
        foreach ($this->data as $key => $row) {
333
334
            if ($max <= $count)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $max does not seem to be defined for all execution paths leading up to this point.
Loading history...
335
                break;
336
337
            $out[$key] = $row;
338
339
            $count++;
340
        }
341
342
        return $this->returnConstant($out);
343
    }
344
345
    /**
346
     * Appends an array to the current one.
347
     *
348
     * @param  array|static $new_rows to append
349
     * @param  callable           $conflict_resolver to use if a new row as the
350
     *                            same key as an existing row. By default, the new
351
     *                            key will be lost and the row appended as natively.
352
     *
353
     * @throws UsageException     If the $new_rows parameter is neither an array
354
     *                            nor a static.
355
     * @return static       $this
356
     */
357
    public function append($new_rows, callable $conflict_resolver=null)
358
    {
359
        if ($new_rows instanceof static)
360
            $new_rows = $new_rows->getArray();
361
362
        if (!is_array($new_rows)) {
363
            $this->throwUsageException(
0 ignored issues
show
Bug introduced by
It seems like throwUsageException() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

363
            $this->/** @scrutinizer ignore-call */ 
364
                   throwUsageException(
Loading history...
364
                "\$new_rows parameter must be an array or an instance of " . __CLASS__
365
            );
366
        }
367
368
        if (!$conflict_resolver) {
369
            // default conflict resolver: append with numeric key
370
            $conflict_resolver = function (&$data, $existing_row, $confliuct_row, $key) {
371
                $data[] = $confliuct_row;
372
            };
373
        }
374
375
        foreach ($new_rows as $key => $new_row) {
376
            if (isset($this->data[$key])) {
377
                $arguments = [
378
                    &$this->data,
379
                    $existing_row,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $existing_row seems to be never defined.
Loading history...
380
                    $confliuct_row,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $confliuct_row seems to be never defined.
Loading history...
381
                    $key
382
                ];
383
384
                call_user_func_array($conflict_resolver, $arguments);
385
            }
386
            else {
387
                $this->data[$key] = $new_row;
0 ignored issues
show
Bug Best Practice introduced by
The property data does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
388
            }
389
        }
390
391
        return $this;
392
    }
393
394
    /**
395
     * @param $columnNames scalar[] The names of the newly created columns.
396
     * @param $options     array    Unsed presently
397
     *
398
     * @see self::dimensionsAsColumns_recurser()
399
     *
400
     * @return static
401
     */
402
    public function dimensionsAsColumns(array $columnNames, array $options=null)
403
    {
404
        $out = $this->dimensionsAsColumns_recurser($this->data, $columnNames);
405
        return $this->returnConstant($out);
406
    }
407
408
    /**
409
     *
410
     * @todo Fix case of other columns
411
     *
412
     * Example:
413
     *  dimensionsAsColumns_recurser([
414
     *      [
415
     *          0,
416
     *          'me',
417
     *      ],
418
     *      [
419
     *          1,
420
     *          'me_too',
421
     *      ],
422
     *  ],
423
     *  [
424
     *      'id',
425
     *      'name',
426
     *  ]
427
     *
428
     * => [
429
     *      'id:0-name:me'     => [
430
     *          'id'   => 0,
431
     *          'name' => 'me',
432
     *      ],
433
     *      'id:1-name:me_too' => [
434
     *          'id'   => 1,
435
     *          'name' => 'me_too',
436
     *      ],
437
     * ]
438
     */
439
    protected function dimensionsAsColumns_recurser(array $data, $columnNames, $rowIdParts=[])
440
    {
441
        $out = [];
442
        // if (!$columnNames)
443
            // return $data;
444
        $no_more_column = !(bool) $columnNames;
0 ignored issues
show
Unused Code introduced by
The assignment to $no_more_column is dead and can be removed.
Loading history...
445
446
        // If all the names have been given to the dimensions
447
        // we compile the index key of the row at the current level
448
        if (empty($columnNames)) {
449
            // echo json_encode([
450
                // 'columnNames' => $columnNames,
451
                // 'rowIdParts'  => $rowIdParts,
452
                // 'data'        => $data,
453
            // ]);
454
            // exit;
455
456
            $indexParts = [];
457
            foreach ($rowIdParts as $name => $value) {
458
                $indexParts[] = $name.':'.$value;
459
            }
460
            $row_id = implode('-', $indexParts);
461
462
            // If we are at a "leaf" of the tree
463
            foreach ($rowIdParts as $name => $value) {
464
                if (isset($data[$name]) && $data[$name] !== $value) {
465
                    self::throwUsageException(
466
                         "Trying to populate a column '$name' that "
467
                        ."already exists with a different value "
468
                        .var_export($data[$name], true). " => '$value'"
469
                    );
470
                }
471
                $data[$name] = $value;
472
            }
473
474
            $out = [
475
                $row_id => $data,
476
            ];
477
478
            return $out;
479
        }
480
481
        $currentDimensionName = array_shift($columnNames);
482
483
        foreach ($data as $key => $row) {
484
485
            // if (!$no_more_column)
486
                $rowIdParts[$currentDimensionName] = $key;
487
            // else
488
                // $rowIdParts[] = $key;
489
490
491
            if (is_array($row)) {
492
                $rows = $this->dimensionsAsColumns_recurser($row, $columnNames, $rowIdParts);
493
                foreach ($rows as $row_id => $joined_row) {
494
                    $out[$row_id] = $joined_row;
495
                }
496
            }
497
            else {
498
499
                if (!isset($rows)) {
500
                    echo json_encode([
501
                        '$rowIdParts' => $rowIdParts,
502
                        '$row' => $row,
503
                    ]);
504
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
505
                }
506
507
                foreach ($rowIdParts as $rowIdPartName => $rowIdPartValue)
508
                    $row[$rowIdPartName] = $rowIdPartValue;
509
510
                $indexParts = [];
511
                foreach ($rowIdParts as $name => $value) {
512
                    $indexParts[] = $name.':'.$value;
513
                }
514
                $row_id = implode('-', $indexParts);
515
516
                $out[$row_id] = $row;
517
            }
518
519
        }
520
521
        return $out;
522
    }
523
524
    /**
525
     * Generates an id usable in hashes to identify a single grouped row.
526
     *
527
     * @param array $row    The row of the array to group by.
528
     * @param array $groups A list of the different groups. Groups can be
529
     *                      strings describing a column name or a callable
530
     *                      function, an array representing a callable,
531
     *                      a function or an integer representing a column.
532
     *                      If the index of the group is a string, it will
533
     *                      be used as a prefix for the group name.
534
     *                      Example:
535
     *                      [
536
     *                          'column_name',
537
     *                          'function_to_call',
538
     *                          4,  //column_number
539
     *                          'group_prefix'  => function($row){},
540
     *                          'group_prefix2' => [$object, 'method'],
541
     *                      ]
542
     *
543
     * @return string       The unique identifier of the group
544
     */
545
    public static function generateGroupId(array $row, array $groups)
546
    {
547
        $group_parts = [];
548
549
        foreach ($groups as $key => $value) {
550
            $part_name = '';
551
552
            if (is_string($key)) {
553
                $part_name .= $key.'_';
554
            }
555
556
            if (is_string($value) && array_key_exists($value, $row)) {
557
                $part_name  .= $value;
558
                $group_value = $row[ $value ];
559
            }
560
            elseif (is_callable($value)) {
561
562
                if (is_string($value)) {
563
                    $part_name  .= $value;
564
                }
565
                // elseif (is_function($value)) {
566
                elseif (is_object($value) && ($value instanceof Closure)) {
0 ignored issues
show
Bug introduced by
The type JClaveau\Arrays\Closure was not found. Did you mean Closure? If so, make sure to prefix the type with \.
Loading history...
567
                    $part_name .= 'unnamed-closure-'
568
                                . hash('crc32b', var_export($value, true));
569
                }
570
                elseif (is_array($value)) {
571
                    $part_name .= implode('::', $value);
572
                }
573
574
                $group_value = call_user_func_array($value, [
575
                    $row, &$part_name
576
                ]);
577
            }
578
            elseif (is_int($value)) {
579
                $part_name  .= $value ? : '0';
580
                $group_value = $row[ $value ];
581
            }
582
            else {
583
                self::throwUsageException(
584
                    'Bad value provided for groupBy id generation: '
585
                    .var_export($value, true)
586
                    ."\n" . var_export($row, true)
587
                );
588
            }
589
590
            if (!is_null($part_name))
591
                $group_parts[ $part_name ] = $group_value;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $group_value does not seem to be defined for all execution paths leading up to this point.
Loading history...
592
        }
593
594
        // sort the groups by names (without it the same group could have multiple ids)
595
        ksort($group_parts);
596
597
        // bidimensional implode
598
        $out = [];
599
        foreach ($group_parts as $group_name => $group_value) {
600
            $out[] = $group_name.':'.$group_value;
601
        }
602
603
        return implode('-', $out);
604
    }
605
606
    /**
607
     * Returns the first element of the array
608
     */
609
    public function first($strict=false)
610
    {
611
        if (!$this->count()) {
0 ignored issues
show
Bug introduced by
It seems like count() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

611
        if (!$this->/** @scrutinizer ignore-call */ count()) {
Loading history...
612
            if ($strict)
613
                throw new \ErrorException("No first element found in this array");
614
            else
615
                $first = null;
616
        }
617
        else {
618
            $key   = key($this->data);
619
            $first = reset($this->data);
620
            $this->move($key);
621
        }
622
623
        return $first;
624
    }
625
626
    /**
627
     * Returns the last element of the array
628
     *
629
     * @todo Preserve the offset
630
     */
631
    public function last($strict=false)
632
    {
633
        if (!$this->count()) {
634
            if ($strict)
635
                throw new \ErrorException("No last element found in this array");
636
            else
637
                $last = null;
638
        }
639
        else {
640
            $key  = key($this->data);
641
            $last = end($this->data);
642
            $this->move($key);
643
        }
644
645
        return $last;
646
    }
647
648
    /**
649
     *
650
     */
651
    public function firstKey($strict=false)
652
    {
653
        if (!$this->count()) {
654
            if ($strict)
655
                throw new \ErrorException("No last element found in this array");
656
            else
657
                $firstKey = null;
658
        }
659
        else {
660
            $key      = key($this->data);
661
            reset($this->data);
662
            $firstKey = key($this->data);
663
            $this->move($key);
664
        }
665
666
        return $firstKey;
667
    }
668
669
    /**
670
     *
671
     */
672
    public function lastKey($strict=false)
673
    {
674
        if (!$this->count()) {
675
            if ($strict)
676
                throw new \ErrorException("No last element found in this array");
677
            else
678
                $lastKey = null;
679
        }
680
        else {
681
            $key  = key($this->data);
682
            end($this->data);
683
            $lastKey = key($this->data);
684
            $this->move($key);
685
        }
686
687
        return $lastKey;
688
    }
689
690
    /**
691
     * Move the internal pointer of the array to the key given as parameter
692
     */
693
    public function move($key, $strict=true)
694
    {
695
        if (array_key_exists($key, $this->data)) {
696
            foreach ($this->data as $i => &$value) {
697
                if ($i === $key) {
698
                    prev($this->data);
699
                    break;
700
                }
701
            }
702
        }
703
        elseif ($strict) {
704
            throw new \ErrorException("Unable to move the internal pointer to a key that doesn't exist.");
705
        }
706
707
        return $this;
708
    }
709
710
    /**
711
     * Chained equivalent of in_array().
712
     * @return bool
713
     */
714
    public function contains($value)
715
    {
716
        return in_array($value, $this->data);
717
    }
718
719
    /**
720
     * Checks if the array is associative or not.
721
     * @return bool
722
     */
723
    public function isAssoc()
724
    {
725
        return Arrays::isAssoc($this->getArray());
0 ignored issues
show
Bug introduced by
The method isAssoc() does not exist on JClaveau\Arrays\Arrays. Did you maybe mean isAssociative()? ( Ignorable by Annotation )

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

725
        return Arrays::/** @scrutinizer ignore-call */ isAssoc($this->getArray());

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...
726
    }
727
728
    /**
729
     * Checks if the array is empty or not.
730
     * @return bool
731
     */
732
    public function isEmpty()
733
    {
734
        return empty($this->getArray());
735
    }
736
737
    /**
738
     * Computes the weighted mean of the values of a column weighted
739
     * by the values of a second one.
740
     *
741
     * @param  string $valueColumnName
742
     * @param  string $weightColumnName
743
     *
744
     * @return float The calculated weighted mean.
745
     */
746
    public function weightedMean($valueColumnName, $weightColumnName)
747
    {
748
        $values  = array_column($this->data, $valueColumnName);
749
        $weights = array_column($this->data, $weightColumnName);
750
751
        return Helper_Math::weightedMean($values, $weights);
0 ignored issues
show
Bug introduced by
The type JClaveau\Arrays\Helper_Math was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
752
    }
753
754
    /**
755
     * Equivalent of var_dump().
756
     *
757
     * @see http://php.net/manual/fr/function.var-dump.php
758
     * @todo Handle xdebug dump formatting
759
     */
760
    public function dump($exit=false)
761
    {
762
        $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
763
        $caller = $bt[0];
764
765
        var_export([
766
            'location' => $caller['file'] . ':' . $caller['line'],
767
            'data'     => $this->data,
768
        ]);
769
770
        if ($exit)
771
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
772
773
        return $this;
774
    }
775
776
    /**
777
     * Scans the array recursivelly (until the max depthis reached) and replaces
778
     * the entries with the callback;
779
     *
780
     * @todo move it to an Arrays class storing static methods
781
     */
782
    public static function replaceEntries(
783
        array $array, callable $replacer, $max_depth=null
784
    ) {
785
        foreach ($array as $key => &$row) {
786
            $arguments = [&$row, $key];
787
            call_user_func_array($replacer, $arguments);
788
789
            if (is_array($row) && $max_depth !== 0) { // allowing null to have no depth limit
790
                $row = self::replaceEntries(
791
                    $row, $replacer, $max_depth ? $max_depth-1 : $max_depth
792
                );
793
            }
794
        }
795
796
        return $array;
797
    }
798
799
    /**
800
     * Equivalent of ->filter() but removes the matching values
801
     *
802
     * @param  callable|array $callback The filter logic with $value and $key
803
     *                            as parameters.
804
     *
805
     * @return static $this or a new static.
806
     */
807
    public function extract($callback=null)
808
    {
809
        if ($callback) {
810
811
            if (is_array($callback)) {
812
                $callback = new \JClaveau\LogicalFilter\LogicalFilter($callback);
0 ignored issues
show
Bug introduced by
The type JClaveau\LogicalFilter\LogicalFilter was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
813
            }
814
815
            if (!is_callable($callback)) {
816
                $this->throwUsageException(
817
                    "\$callback must be a logical filter description array or a callable"
818
                    ." instead of "
819
                    .var_export($callback, true)
820
                );
821
            }
822
823
            $out = [];
824
            foreach ($this->data as $key => $value) {
825
                if ($callback($value, $key)) {
826
                    $out[$key] = $value;
827
                    unset( $this->data[$key] );
828
                }
829
            }
830
        }
831
832
        return new static($out);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $out does not seem to be defined for all execution paths leading up to this point.
Loading history...
Unused Code introduced by
The call to JClaveau\Arrays\Chainabl...ls_Trait::__construct() has too many arguments starting with $out. ( Ignorable by Annotation )

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

832
        return /** @scrutinizer ignore-call */ new static($out);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
833
    }
834
835
    /**/
836
}
837