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