1<?php
2
3namespace Elastica\Bulk\Action;
4
5use Elastica\AbstractUpdateAction;
6use Elastica\Bulk\Action;
7use Elastica\Document;
8use Elastica\Script\AbstractScript;
9
10abstract class AbstractDocument extends Action
11{
12    /**
13     * @var Document|AbstractScript
14     */
15    protected $_data;
16
17    /**
18     * @param Document|AbstractScript $document
19     */
20    public function __construct($document)
21    {
22        $this->setData($document);
23    }
24
25    /**
26     * @param Document $document
27     *
28     * @return $this
29     */
30    public function setDocument(Document $document): self
31    {
32        $this->_data = $document;
33
34        $metadata = $this->_getMetadata($document);
35
36        $this->setMetadata($metadata);
37
38        return $this;
39    }
40
41    /**
42     * @param AbstractScript $script
43     *
44     * @return $this
45     */
46    public function setScript(AbstractScript $script): self
47    {
48        if (!$this instanceof UpdateDocument) {
49            throw new \BadMethodCallException('setScript() can only be used for UpdateDocument');
50        }
51
52        $this->_data = $script;
53
54        $metadata = $this->_getMetadata($script);
55        $this->setMetadata($metadata);
56
57        return $this;
58    }
59
60    /**
61     * @param AbstractScript|Document $data
62     *
63     * @throws \InvalidArgumentException
64     *
65     * @return $this
66     */
67    public function setData($data): self
68    {
69        if ($data instanceof AbstractScript) {
70            $this->setScript($data);
71        } elseif ($data instanceof Document) {
72            $this->setDocument($data);
73        } else {
74            throw new \InvalidArgumentException('Data should be a Document or a Script.');
75        }
76
77        return $this;
78    }
79
80    /**
81     * Note: This is for backwards compatibility.
82     *
83     * @return Document|null
84     */
85    public function getDocument()
86    {
87        if (!$this->_data instanceof Document) {
88            return null;
89        }
90
91        return $this->_data;
92    }
93
94    /**
95     * Note: This is for backwards compatibility.
96     *
97     * @return AbstractScript|null
98     */
99    public function getScript()
100    {
101        if (!$this->_data instanceof AbstractScript) {
102            return null;
103        }
104
105        return $this->_data;
106    }
107
108    /**
109     * @return Document|AbstractScript
110     */
111    public function getData()
112    {
113        return $this->_data;
114    }
115
116    /**
117     * @param AbstractUpdateAction $source
118     *
119     * @return array
120     */
121    abstract protected function _getMetadata(AbstractUpdateAction $source): array;
122
123    /**
124     * Creates a bulk action for a document or a script.
125     *
126     * The action can be index, update, create or delete based on the $opType param (by default index).
127     *
128     * @param Document|AbstractScript $data
129     * @param string                  $opType
130     *
131     * @return static
132     */
133    public static function create($data, string $opType = null): self
134    {
135        //Check type
136        if (!$data instanceof Document && !$data instanceof AbstractScript) {
137            throw new \InvalidArgumentException('The data needs to be a Document or a Script.');
138        }
139
140        if (null === $opType && $data->hasOpType()) {
141            $opType = $data->getOpType();
142        }
143
144        //Check that scripts can only be used for updates
145        if ($data instanceof AbstractScript) {
146            if (null === $opType) {
147                $opType = self::OP_TYPE_UPDATE;
148            } elseif (self::OP_TYPE_UPDATE !== $opType) {
149                throw new \InvalidArgumentException('Scripts can only be used with the update operation type.');
150            }
151        }
152
153        switch ($opType) {
154            case self::OP_TYPE_DELETE:
155                $action = new DeleteDocument($data);
156                break;
157
158            case self::OP_TYPE_CREATE:
159                $action = new CreateDocument($data);
160                break;
161
162            case self::OP_TYPE_UPDATE:
163                $action = new UpdateDocument($data);
164                break;
165
166            case self::OP_TYPE_INDEX:
167            default:
168                $action = new IndexDocument($data);
169                break;
170        }
171
172        return $action;
173    }
174}
175