1<?php
2
3namespace Elastica\Aggregation;
4
5use Elastica\Exception\InvalidException;
6use Elastica\NameableInterface;
7use Elastica\Param;
8use Elastica\Util;
9
10abstract class AbstractAggregation extends Param implements NameableInterface
11{
12    protected const METADATA_KEY = 'meta';
13
14    /**
15     * @var string The name of this aggregation
16     */
17    protected $_name;
18
19    /**
20     * @var array Subaggregations belonging to this aggregation
21     */
22    protected $_aggs = [];
23
24    /**
25     * @param string $name the name of this aggregation
26     */
27    public function __construct(string $name)
28    {
29        $this->setName($name);
30    }
31
32    /**
33     * Set the name of this aggregation.
34     *
35     * @return $this
36     */
37    public function setName(string $name): NameableInterface
38    {
39        $this->_name = $name;
40
41        return $this;
42    }
43
44    /**
45     * Retrieve the name of this aggregation.
46     */
47    public function getName(): string
48    {
49        return $this->_name;
50    }
51
52    /**
53     * Retrieve all subaggregations belonging to this aggregation.
54     */
55    public function getAggs(): array
56    {
57        return $this->_aggs;
58    }
59
60    /**
61     * Add a sub-aggregation.
62     *
63     * @throws InvalidException
64     *
65     * @return $this
66     */
67    public function addAggregation(AbstractAggregation $aggregation): self
68    {
69        if ($aggregation instanceof GlobalAggregation) {
70            throw new InvalidException('Global aggregators can only be placed as top level aggregators');
71        }
72
73        $this->_aggs[] = $aggregation;
74
75        return $this;
76    }
77
78    /**
79     * Add metadata to the aggregation.
80     *
81     * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/agg-metadata.html
82     * @see \Elastica\Aggregation\AbstractAggregation::getMeta()
83     * @see \Elastica\Aggregation\AbstractAggregation::clearMeta()
84     *
85     * @param array $meta Metadata to be attached to the aggregation
86     *
87     * @return $this
88     */
89    public function setMeta(array $meta): self
90    {
91        if (!$meta) {
92            return $this->clearMeta();
93        }
94
95        $this->_setRawParam(self::METADATA_KEY, $meta);
96
97        return $this;
98    }
99
100    /**
101     * Retrieve the currently configured metadata for the aggregation.
102     *
103     * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/agg-metadata.html
104     * @see \Elastica\Aggregation\AbstractAggregation::setMeta()
105     * @see \Elastica\Aggregation\AbstractAggregation::clearMeta()
106     */
107    public function getMeta(): ?array
108    {
109        return $this->_rawParams[self::METADATA_KEY] ?? null;
110    }
111
112    /**
113     * Clears any previously set metadata for this aggregation.
114     *
115     * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/agg-metadata.html
116     * @see \Elastica\Aggregation\AbstractAggregation::setMeta()
117     * @see \Elastica\Aggregation\AbstractAggregation::getMeta()
118     *
119     * @return $this
120     */
121    public function clearMeta(): self
122    {
123        unset($this->_rawParams[self::METADATA_KEY]);
124
125        return $this;
126    }
127
128    public function toArray(): array
129    {
130        $array = parent::toArray();
131
132        if (\count($this->_aggs)) {
133            $array['aggs'] = $this->_convertArrayable($this->_aggs);
134        }
135
136        return $array;
137    }
138
139    protected function _getBaseName()
140    {
141        $shortName = (new \ReflectionClass($this))->getShortName();
142        $shortName = \preg_replace('/Aggregation$/', '', $shortName);
143
144        return Util::toSnakeCase($shortName);
145    }
146}
147