Completed
Branch feature/pre-split (8b986a)
by Anton
06:31
created

AggregationHelper::findValue()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 6
nop 1
dl 0
loc 32
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework, Core Components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\ODM\Helpers;
8
9
use Spiral\Models\AccessorInterface;
10
use Spiral\Models\EntityInterface;
11
use Spiral\ODM\CompositableInterface;
12
use Spiral\ODM\DocumentEntity;
13
use Spiral\ODM\Entities\DocumentSelector;
14
use Spiral\ODM\ODMInterface;
15
use Spiral\ODM\Schemas\Definitions\AggregationDefinition;
16
17
/**
18
 * Provides ability to configure ODM Selector based on values and query template provided by source
19
 * model.
20
 *
21
 * @todo add sorts and limits
22
 * @todo implement on query level?
23
 * @see  AggregationDefinition
24
 */
25
class AggregationHelper
26
{
27
    /**
28
     * @var array
29
     */
30
    private $schema = [];
31
32
    /**
33
     * @var DocumentEntity
34
     */
35
    protected $source;
36
37
    /**
38
     * @var ODMInterface
39
     */
40
    protected $odm;
41
42
    /**
43
     * @param DocumentEntity $source
44
     * @param ODMInterface   $odm
45
     */
46
    public function __construct(DocumentEntity $source, ODMInterface $odm)
47
    {
48
        $this->schema = (array)$odm->define(get_class($source), ODMInterface::D_SCHEMA);
49
        $this->source = $source;
50
        $this->odm = $odm;
51
    }
52
53
    /**
54
     * Create aggregation (one or many) based on given source values.
55
     *
56
     * @param string $aggregation
57
     *
58
     * @return DocumentSelector|CompositableInterface
59
     */
60
    public function createAggregation(string $aggregation)
61
    {
62
        $schema = $this->schema[DocumentEntity::SH_AGGREGATIONS][$aggregation];
63
64
        //Let's create selector
65
        $selector = $this->odm->selector($schema[1]);
66
67
        //Ensure selection query
68
        $selector = $this->configureSelector($selector, $schema);
69
70
        if ($schema[0] == DocumentEntity::ONE) {
71
            return $selector->findOne();
72
        }
73
74
        return $selector;
75
    }
76
77
    /**
78
     * Configure DocumentSelector using aggregation schema.
79
     *
80
     * @param DocumentSelector $selector
81
     * @param array            $aggregation
82
     *
83
     * @return DocumentSelector
84
     */
85
    protected function configureSelector(
86
        DocumentSelector $selector,
87
        array $aggregation
88
    ): DocumentSelector {
89
        //@see AggregationDefinition
90
        $query = $aggregation[2];
91
92
        //Mounting selection values
93
        array_walk_recursive($query, function (&$value) {
94
            if (strpos($value, 'self::') === 0) {
95
                $value = $this->findValue(substr($value, 6));
96
            }
97
        });
98
99
        return $selector->where($query);
100
    }
101
102
    /**
103
     * Find field value using dot notation.
104
     *
105
     * @param string $name
106
     *
107
     * @return mixed|null
108
     */
109
    private function findValue(string $name)
110
    {
111
        $source = $this->source;
112
113
        $path = explode('.', $name);
114
        foreach ($path as $step) {
115
            if ($source instanceof EntityInterface) {
116
                if (!$source->hasField($step)) {
117
                    return null;
118
                }
119
120
                //Sub entity or field
121
                $source = $source->getField($step);
122
                continue;
123
            }
124
125
            if ($source instanceof AccessorInterface) {
126
                $source = $source->packValue();
127
                continue;
128
            }
129
130
            if (is_array($source) && array_key_exists($step, $source)) {
131
                $source = &$source[$step];
132
                continue;
133
            }
134
135
            //Unable to resolve value, an exception required here
136
            return null;
137
        }
138
139
        return $source;
140
    }
141
}