ArchiveTransferValidationTrait.php 15.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
/*
 * Copyright (C) 2015 Maarch
 *
 * This file is part of bundle seda.
 *
 * Bundle seda is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Bundle seda is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with bundle seda.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace ext\archivesPubliques\bundle\seda2\Controller;

/**
 * Class ArchiveTransfer
 *
 * @package Seda
 */
trait ArchiveTransferValidationTrait
{
    /**
     * Validate against profile
     * @param seda/message $message           The message object with the xml
     * @param object       $archivalAgreement The archival agreement
     *
     * @return boolean The result of the operation
     */
    public function validate($message, $archivalAgreement = null)
    {
        $this->errors = array();
        $this->replyCode = null;

        $this->loadMessage($message);

        if (!empty($archivalAgreement)) {
            if ($archivalAgreement->originatorOrgIds) {
                $this->validateOriginators($message, $archivalAgreement);
            }
            if ($archivalAgreement->signed && !isset($message->object->signature)) {
                $this->sendError("309");
            }
            if (isset($archivalAgreement->archivalProfileReference)
                || isset($message->object->dataObjectPackage->managementMetadata->archivalProfile->value)) {
                $this->validateProfile($this->message, $archivalAgreement);
            }
55
            if (isset($message->object->dataObjectPackage->managementMetadata->serviceLevel->value)
56
                && $message->object->dataObjectPackage->managementMetadata->serviceLevel->value != $archivalAgreement->serviceLevelReference) {
57
58
59
60
61
62
63
64
                $serviceLevelReference = $message->object->dataObjectPackage->managementMetadata->serviceLevel->value;
                $this->sendError("203", "Le niveau de service du bordereau $serviceLevelReference ne correspond pas à celui de l'accord de versement");
            }
        }

        if (!empty($message->object->dataObjectPackage->managementMetadata->serviceLevel->value)) {
            $serviceLevelRef = $message->object->dataObjectPackage->managementMetadata->serviceLevel->value;
            try {
65
                $serviceLevel = $this->serviceLevelController->getByReference($serviceLevelRef);
66
67
            } catch (\Exception $e) {
                $this->sendError("203", "Le niveau de service du bordereau $serviceLevelRef est inconnu du système");
68
            }
69
70
71
72
        }

        // Contrôle des documents attachés
        $this->validateAttachments($this->message, $archivalAgreement);
73
        $this->validateRules($this->message, $this->message->object->dataObjectPackage->descriptiveMetadata->archiveUnit);
74
75
76
77

        return true;
    }

78
    protected function validateRules($message, $archives)
79
80
    {
        foreach ($archives as $archive) {
81
82
83
84
85
86
            if (isset($archive->management->appraisalRule->rule) && !empty($archive->management->appraisalRule->rule)) {
                foreach ($archive->management->appraisalRule->rule as $ruleObject) {
                    $ruleSdo = $this->retentionRuleController->read($ruleObject->value);
                    if (!isset($ruleSdo) || empty($ruleSdo)) {
                        $this->sendError("404", "La règle de conservation '$ruleObject->value' n'a pas pu être transmise");
                    }
87
88
                }
            }
89
90
            if (isset($archive->management->accessRule->rule) && !empty($archive->management->accessRule->rule)) {
                foreach ($archive->management->accessRule->rule as $ruleObject) {
Alexandre Morin's avatar
Alexandre Morin committed
91
92
                    $ruleSdo = $this->accessRuleController->edit($ruleObject->value);
                    if (!isset($ruleSdo) || empty($ruleSdo)) {
93
94
                        $this->sendError("404", "La règle de communicabilité '$ruleObject->value' n'a pas pu être transmise");
                    }
95
96
                }
            }
97

98
            if (isset($archive->archiveUnit)) {
99
                $this->validateRules($message, $archive->archiveUnit);
100
            }
101
102
103
        }
    }

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    protected function validateOriginators($message, $archivalAgreement)
    {
        // Contrôle du producteur
        $originatorIdentifications = array();
        if (isset($message->object->dataObjectPackage->managementMetadata->originatingAgencyIdentifier) && !empty($message->object->dataObjectPackage->managementMetadata->originatingAgencyIdentifier->value)) {
            $originatorIdentifications[] = $message->object->dataObjectPackage->managementMetadata->originatingAgencyIdentifier->value;
        }
        foreach ($message->object->dataObjectPackage->descriptiveMetadata->archiveUnit as $archive) {
            $originatorIdentifications = array_merge($originatorIdentifications, $this->getOriginatorIdentifications($archive));
        }

        $originatorIdentifications = array_unique($originatorIdentifications);

        $originatorOrgs = array();

        foreach ($originatorIdentifications as $originatorIdentification) {
            //$originatorOrgRegNumber = $originatorOrgRegNumberElement->nodeValue;
            if (!isset($originatorOrgs[$originatorIdentification])) {
                try {
                    $originatorOrg = $this->orgController->getOrgByRegNumber($originatorIdentification);
                    $originatorOrgs[$originatorIdentification] = $originatorOrg;
                } catch (\Exception $e) {
                    $this->sendError("200", "Le producteur de l'archive identifié par '$originatorIdentification' n'est pas référencé dans le système.");

                    continue;
                }

                if (!in_array('originator', (array) $originatorOrg->orgRoleCodes)) {
                    $this->sendError("302", "Le service identifié par '$originatorIdentification' n'est pas référencé comme producteur dans le système.");
                }

                if (!in_array((string) $originatorOrg->orgId, (array) $archivalAgreement->originatorOrgIds)) {
                    $this->sendError("302", "Le producteur de l'archive identifié par '$originatorIdentification' n'est pas indiqué dans l'accord de versement.");
                }
138
139

                if (!$originatorOrg->enabled) {
140
                    $this->sendError("302", "Le service producteur '$originatorIdentification' est désactivé : veuillez le réactiver pour pouvoir verser des archives");
141
                }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
            }
        }
    }

    protected function getOriginatorIdentifications($archive)
    {
        $originatorIdentifications = array();

        if (isset($archive->content->originatingAgency) && !empty($archive->content->originatingAgency->identifier->value)) {
            $originatorIdentifications[] = $archive->content->originatingAgency->identifier->value;
        }

        if (isset($archive->archiveUnit)) {
            foreach ($archive->archiveUnit as $archiveUnit) {
                $originatorIdentifications = array_merge($originatorIdentifications, $this->getOriginatorIdentifications($archiveUnit));
            }
        }

        return array_unique($originatorIdentifications);
    }

    protected function validateProfile($message, $archivalAgreement)
    {
        // No agreement and no profile
        if (!$archivalAgreement && !isset($message->object->dataObjectPackage->managementMetadata->archivalProfile->value)) {
            $this->sendError("203");

            return;
        }

        // Aggreement but no profile
        if (!isset($message->object->dataObjectPackage->managementMetadata->archivalProfile->value)) {
            $archivalprofileReference = $archivalAgreement->archivalProfileReference;
        } else {
            $archivalprofileReference = $message->object->dataObjectPackage->managementMetadata->archivalProfile->value;

            if ($archivalAgreement && $archivalprofileReference != $archivalAgreement->archivalProfileReference) {
                $this->sendError("203", "Le profil d'archive du bordereau $archivalprofileReference ne correspond pas à celui de l'accord de versement");

                return;
            }
        }

        $configuration = \laabs::configuration('recordsManagement');

        if ($configuration['archivalProfileType'] == '1' || $configuration['archivalProfileType'] == '3') {
            // Profile is based on an XSD or RelaxNG file
            $profileFiles = glob($this->profilesDirectory.DIRECTORY_SEPARATOR.$archivalprofileReference.'.*');

            if (count($profileFiles) == 0 && $configuration['archivalProfileType'] == '1') {
                $this->sendError("203", "Le message fait référence à un profil d'archive $archivalprofileReference non enregistré dans le système.");

                return;
            }

            foreach ($profileFiles as $profileFile) {
                $extension = pathinfo($profileFile, \PATHINFO_EXTENSION);

                switch ($extension) {
                    case 'rng':
                        //if ($validationMode == 'jing') {
                        if (true) {
                            $jing = \laabs::newService('dependency/xml/plugins/jing/jing');
                            $valid = $jing->validate($profileFile, $this->message->path);
                            if (!$valid) {
                                $this->sendError("203");

                                if ($jing->getErrors()) {
                                    foreach ($jing->getErrors() as $errorMessage) {
                                        $this->errors[] = new \core\error($errorMessage);
                                    }
                                }
                            }
                        } else {
                            libxml_use_internal_errors(true);
                            $valid = $message->xml->relaxNGValidate($profileFile);
                            if ($valid == false) {
                                $this->sendError("203");
                                foreach (libxml_get_errors() as $libxmlError) {
                                    $this->errors[] = new \core\error($libxmlError->message, null, $libxmlError->code);
                                }
                            }
                            libxml_clear_errors();
                            libxml_use_internal_errors(false);
                        }
                        break;

                    case 'xsd':
                        libxml_use_internal_errors(true);
                        $valid = $message->xml->schemaValidate($profileFile);
                        if ($valid == false) {
                            foreach (libxml_get_errors() as $libxmlError) {
                                $this->errors[] = new \core\error($libxmlError->message, null, $libxmlError->code);
                            }
                        }
                        libxml_clear_errors();
                        libxml_use_internal_errors(false);
                        break;
                    default:
241
242
243
244
245
                        $path = $this->profilesDirectory.DIRECTORY_SEPARATOR.$archivalprofileReference;
                        // if a profile were previously saved without extension
                        if (empty($extension) && (file_exists($path . '.rng') || file_exists($path . '.xsd'))) {
                            break;
                        }
246
                        $this->sendError("203", "Le message fait référence à un profil d'archive dont le format n'est pas géré.");
247
                        break;
248
249
250
251
252
253
254
255
256
                }
            }
        }
    }

    protected function validateAttachments($message, $archivalAgreement)
    {
        $serviceLevelController = \laabs::newController("recordsManagement/serviceLevel");

257
258
259
        $dataObjectPackage = $message->object->dataObjectPackage;
        if (isset($dataObjectPackage->managementMetadata->serviceLevel)) {
            $serviceLevelReference = $dataObjectPackage->managementMetadata->serviceLevel->value;
260
261
262
263
        } elseif (isset($archivalAgreement)) {
            $serviceLevelReference = $archivalAgreement->serviceLevelReference;
        }

264
        if (!isset($serviceLevelReference) || empty($serviceLevelReference)) {
265
266
            $serviceLevelByDefault = $this->sdoFactory->find('recordsManagement/serviceLevel', 'default= true');

267
            if (!isset($serviceLevelByDefault) || empty($serviceLevelByDefault)) {
268
269
270
271
272
273
274
275
276
                $this->sendError("203", "Le niveau de service n'est pas renseigné.");

                return;
            }

            $serviceLevel = $serviceLevelByDefault[0];
        } else {
            $serviceLevel = $serviceLevelController->getByReference($serviceLevelReference);
        }
277
278
279
280
281
282
283
284

        $formatController = \laabs::newController("digitalResource/format");
        if ($archivalAgreement) {
            $allowedFormats = \laabs\explode(' ', $archivalAgreement->allowedFormats);
        } else {
            $allowedFormats = [];
        }

285
286
287
288
289
290
291
292
293
        $binaryDataObjects = (array) $dataObjectPackage->binaryDataObject;
        if (isset($dataObjectPackage->dataObjectGroup)) {
            foreach ((array)$dataObjectPackage->dataObjectGroup as $dataObjectGroup) {
                if (!isset($dataObjectGroup->binaryDataObject)) {
                    continue;
                }
                $binaryDataObjects = array_merge($binaryDataObjects, $dataObjectGroup->binaryDataObject);
            }
        }
294
295
296
297
298
299

        $messageDir = dirname($message->path);        // List received files

        // List actual message files, starting with message xml itself
        $messageFiles = array($messageDir.DIRECTORY_SEPARATOR.(string) $message->messageId.".xml");
        if (count($binaryDataObjects)) {
300
301
302
303
304
            foreach ($binaryDataObjects as $binaryDataObject) {
                $filepath = $messageDir.DIRECTORY_SEPARATOR.$binaryDataObject->uri;

                if (!isset($binaryDataObject->formatIdentification)) {
                    $binaryDataObject->formatIdentification = new \StdClass();
305
306
307
308
309
310
                }

                if (strpos($serviceLevel->control, 'formatDetection') !== false) {
                    $format = $formatController->identifyFormat($filepath);

                    if (!$format) {
311
                        $this->sendError("205", "Le format du document '".$binaryDataObject->uri."' n'a pas pu être déterminé");
312
313
                    } else {
                        $puid = $format->puid;
314
                        $binaryDataObject->formatIdentification->formatId = $puid;
315
316
317
318
319
                    }
                }

                // Validate format is allowed
                if (count($allowedFormats) && isset($puid) && !in_array($puid, $allowedFormats)) {
320
                    $this->sendError("307", "Le format du document '".$binaryDataObject->uri."' ".$puid." n'est pas autorisé par l'accord de versement.");
321
                }
322

323
324
325
326
                // Validate format
                if (strpos($serviceLevel->control, 'formatValidation') !== false) {
                    $validation = $formatController->validateFormat($filepath);
                    if (!$validation !== true && is_array($validation)) {
327
                        $this->sendError("307", "Le format du document '".$binaryDataObject->uri."' n'est pas valide : ".implode(', ', $validation));
328
329
330
331
332
333
334
                    }
                    $this->infos[] = (string) \laabs::newDateTime().": Validation du format par JHOVE 1.11";
                }
            }
        }
    }

335

336
}