1<?php
2
3
4namespace ComboStrap;
5
6
7use ComboStrap\Meta\Api\Metadata;
8use ComboStrap\Meta\Api\MetadataStore;
9
10class MetadataStoreTransfer
11{
12    const CANONICAL = "meta-store-transfer";
13
14    /**
15     * @var MetadataStore
16     */
17    private $sourceStore;
18    /**
19     * @var MetadataStore
20     */
21    private $targetStore;
22
23    /**
24     * @var MarkupPath
25     */
26    private $page;
27
28
29    /**
30     * @var array - the processing messages
31     */
32    private array $messages = [];
33
34    /**
35     * @var array - the validated metadata (that may be stored)
36     */
37    private array $metadatasThatMayBeStored;
38
39    /**
40     * @var Metadata[] - the original metas (no default as we check if they were already set)
41     */
42    private array $originalMetadatas;
43
44    /**
45     * MetadataStoreTransfer constructor.
46     * @param MarkupPath $resource
47     */
48    public function __construct(ResourceCombo $resource)
49    {
50        $this->page = $resource;
51    }
52
53
54    public static function createForPage($page): MetadataStoreTransfer
55    {
56        return new MetadataStoreTransfer($page);
57    }
58
59    /**
60     * @return $this - validate the transfer (ie the metadatas). The metadata that can be retrieved via {@link self::getValidatedMetadatas()}
61     * and the bad validation messages if any via {@link self::getMessages()}
62     */
63    public function validate(): MetadataStoreTransfer
64    {
65
66        if (isset($this->metadatasThatMayBeStored)) {
67            return $this;
68        }
69        if (!isset($this->originalMetadatas)) {
70            throw new ExceptionRuntimeInternal("The original metadata should be defined");
71        }
72
73        $this->metadatasThatMayBeStored = [];
74        foreach ($this->originalMetadatas as $originalMetaKey => $originalMetaValue) {
75
76
77            try {
78                $metadataObject = Meta\Api\MetadataSystem::getForName($originalMetaKey);
79            } catch (ExceptionNotFound $e) {
80                LogUtility::warning("The meta ($originalMetaKey) was not found", self::CANONICAL, $e);
81                continue;
82            }
83
84            /**
85             * Take old name or renaming into account
86             *
87             * ie The old key should be replace by the new one
88             * (ie {@link \ComboStrap\PagePublicationDate::OLD_META_KEY}
89             * by {@link \ComboStrap\PagePublicationDate::PROPERTY_NAME}
90             */
91            $name = $originalMetaKey;
92            if ($metadataObject !== null) {
93                $name = $metadataObject::getName();
94                $originalMetaKey = $metadataObject::getPersistentName();
95            }
96
97            /**
98             * Not modifiable meta check
99             */
100            if (in_array($name, Metadata::NOT_MODIFIABLE_METAS)) {
101                $this->messages[] = Message::createWarningMessage("The metadata ($name) is a protected metadata and cannot be modified")
102                    ->setCanonical(Metadata::CANONICAL);
103                continue;
104            }
105
106            /**
107             * Unknown meta
108             */
109            if ($metadataObject === null) {
110                $this->messages[] = Message::createWarningMessage("The metadata ($originalMetaKey) is unknown and was not persisted")->setCanonical(Metadata::CANONICAL);
111                continue;
112            }
113
114
115            /**
116             * We build and not set with {@link Metadata::setFromStoreValue()}
117             * because tabular data in forms have several key by columns (ie on key is a column
118             * that may have several values)
119             * Therefore tabular data needs to get access to the whole source store
120             * to be build
121             */
122            $metadataObject
123                ->setResource($this->page)
124                ->setReadStore($this->sourceStore)
125                ->setWriteStore($this->targetStore)
126                ->buildFromReadStore();
127
128            $this->metadatasThatMayBeStored[$name] = $metadataObject;
129
130        }
131        return $this;
132    }
133
134    public function fromStore(MetadataStore $sourceStore): MetadataStoreTransfer
135    {
136        $this->sourceStore = $sourceStore;
137        return $this;
138    }
139
140    public function toStore(MetadataStore $targetStore): MetadataStoreTransfer
141    {
142        $this->targetStore = $targetStore;
143        return $this;
144    }
145
146    /**
147     * @param Metadata[]|null $data - the metadadata (@deprecate for {@link self::setMetadatas()}
148     * @return $this
149     */
150    public function process(array $data = null): MetadataStoreTransfer
151    {
152
153        /**
154         * We may use this object to validate, setting before the processing
155         */
156        if (isset($this->originalMetadatas) && $data !== null) {
157            throw new ExceptionRuntimeInternal("The metadata to process were already set");
158        } else {
159            $this->originalMetadatas = $data;
160        }
161        $messages = [];
162
163        /**
164         * Pre-processing
165         * Check/ validity and list of metadata building
166         */
167        $validatedMetadata = $this->validate()->getValidatedMetadatas();
168
169        foreach ($validatedMetadata as $metadata) {
170
171            /**
172             * Persistent ?
173             */
174            if ($metadata->getPersistenceType() !== Metadata::PERSISTENT_METADATA) {
175                $messages[] = Message::createWarningMessage("The metadata ({$metadata->getName()}) is not persistent and cannot be modified")
176                    ->setCanonical($metadata->getCanonical());
177                continue;
178            }
179
180            /**
181             * Sync
182             */
183            try {
184                $metadata->sendToWriteStore();
185            } catch (ExceptionCompile $e) {
186                $messages[] = Message::createErrorMessage("Error while replicating the meta ($metadata) from the store ($this->sourceStore) to the store ($this->targetStore). Message: " . $e->getMessage())
187                    ->setCanonical($metadata->getCanonical());
188            }
189        }
190        $this->targetStore->persist();
191
192        $this->messages = $messages;
193        return $this;
194    }
195
196    /**
197     * @return Message[]
198     */
199    public function getMessages(): array
200    {
201        return $this->messages;
202    }
203
204
205    /**
206     * @return Metadata[] - an array where the key is the name and the value a {@link Metadata} object
207     */
208    public function getValidatedMetadatas(): array
209    {
210        if (!isset($this->metadatasThatMayBeStored)) {
211            $this->validate();
212        }
213        return $this->metadatasThatMayBeStored;
214    }
215
216    /**
217     * @param Metadata[] $originalMetadatas
218     * @return $this
219     */
220    public function setMetadatas(array $originalMetadatas): MetadataStoreTransfer
221    {
222        $this->originalMetadatas = $originalMetadatas;
223        return $this;
224    }
225
226
227}
228