1<?php
2
3namespace Elastica\Bulk;
4
5use Elastica\Bulk;
6use Elastica\Index;
7use Elastica\JSON;
8use Elastica\Type;
9
10class Action
11{
12    const OP_TYPE_CREATE = 'create';
13    const OP_TYPE_INDEX = 'index';
14    const OP_TYPE_DELETE = 'delete';
15    const OP_TYPE_UPDATE = 'update';
16
17    /**
18     * @var array
19     */
20    public static $opTypes = [
21        self::OP_TYPE_CREATE,
22        self::OP_TYPE_INDEX,
23        self::OP_TYPE_DELETE,
24        self::OP_TYPE_UPDATE,
25    ];
26
27    /**
28     * @var string
29     */
30    protected $_opType;
31
32    /**
33     * @var array
34     */
35    protected $_metadata = [];
36
37    /**
38     * @var array
39     */
40    protected $_source = [];
41
42    /**
43     * @param string $opType
44     * @param array  $metadata
45     * @param array  $source
46     */
47    public function __construct(string $opType = self::OP_TYPE_INDEX, array $metadata = [], array $source = [])
48    {
49        $this->setOpType($opType);
50        $this->setMetadata($metadata);
51        $this->setSource($source);
52    }
53
54    /**
55     * @param string $type
56     *
57     * @return $this
58     */
59    public function setOpType(string $type): self
60    {
61        $this->_opType = $type;
62
63        return $this;
64    }
65
66    /**
67     * @return string
68     */
69    public function getOpType(): string
70    {
71        return $this->_opType;
72    }
73
74    /**
75     * @param array $metadata
76     *
77     * @return $this
78     */
79    public function setMetadata(array $metadata): self
80    {
81        $this->_metadata = $metadata;
82
83        return $this;
84    }
85
86    /**
87     * @return array
88     */
89    public function getMetadata(): array
90    {
91        return $this->_metadata;
92    }
93
94    /**
95     * @return array
96     */
97    public function getActionMetadata(): array
98    {
99        return [$this->_opType => $this->getMetadata()];
100    }
101
102    /**
103     * @param array|string $source
104     *
105     * @return $this
106     */
107    public function setSource($source): self
108    {
109        $this->_source = $source;
110
111        return $this;
112    }
113
114    /**
115     * @return array|string
116     */
117    public function getSource()
118    {
119        return $this->_source;
120    }
121
122    /**
123     * @return bool
124     */
125    public function hasSource(): bool
126    {
127        return !empty($this->_source);
128    }
129
130    /**
131     * @param string|Index $index
132     *
133     * @return $this
134     */
135    public function setIndex($index): self
136    {
137        if ($index instanceof Index) {
138            $index = $index->getName();
139        }
140        $this->_metadata['_index'] = $index;
141
142        return $this;
143    }
144
145    /**
146     * @param string|Type $type
147     *
148     * @return $this
149     */
150    public function setType($type): self
151    {
152        if ($type instanceof Type) {
153            $this->setIndex($type->getIndex()->getName());
154            $type = $type->getName();
155        }
156        $this->_metadata['_type'] = $type;
157
158        return $this;
159    }
160
161    /**
162     * @param string|int $id
163     *
164     * @return $this
165     */
166    public function setId($id): self
167    {
168        $this->_metadata['_id'] = $id;
169
170        return $this;
171    }
172
173    /**
174     * @param string|int $routing
175     *
176     * @return $this
177     */
178    public function setRouting($routing): self
179    {
180        $this->_metadata['routing'] = $routing;
181
182        return $this;
183    }
184
185    /**
186     * @return array
187     */
188    public function toArray(): array
189    {
190        $data[] = $this->getActionMetadata();
191        if ($this->hasSource()) {
192            $data[] = $this->getSource();
193        }
194
195        return $data;
196    }
197
198    /**
199     * @return string
200     */
201    public function toString(): string
202    {
203        $string = JSON::stringify($this->getActionMetadata(), JSON_FORCE_OBJECT).Bulk::DELIMITER;
204        if ($this->hasSource()) {
205            $source = $this->getSource();
206            if (\is_string($source)) {
207                $string .= $source;
208            } elseif (\is_array($source) && \array_key_exists('doc', $source) && \is_string($source['doc'])) {
209                if (isset($source['doc_as_upsert'])) {
210                    $docAsUpsert = ', "doc_as_upsert": '.($source['doc_as_upsert'] ? 'true' : 'false');
211                } else {
212                    $docAsUpsert = '';
213                }
214                $string .= '{"doc": '.$source['doc'].$docAsUpsert.'}';
215            } else {
216                $string .= JSON::stringify($source, JSON_UNESCAPED_UNICODE);
217            }
218            $string .= Bulk::DELIMITER;
219        }
220
221        return $string;
222    }
223
224    /**
225     * @param string|null $opType
226     *
227     * @return bool
228     */
229    public static function isValidOpType(string $opType = null): bool
230    {
231        return \in_array($opType, self::$opTypes, true);
232    }
233}
234