Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
EntitySchemaUpdateGuard
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
4 / 4
7
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 guardSchemaUpdate
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 cleanupData
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 array2persistence
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare( strict_types = 1 );
4
5namespace EntitySchema\DataAccess;
6
7use Diff\Patcher\PatcherException;
8use EntitySchema\Services\Converter\EntitySchemaConverter;
9use EntitySchema\Services\Converter\FullArrayEntitySchemaData;
10use EntitySchema\Services\Converter\PersistenceEntitySchemaData;
11use EntitySchema\Services\Diff\EntitySchemaDiffer;
12use EntitySchema\Services\Diff\EntitySchemaPatcher;
13use MediaWiki\Revision\RevisionRecord;
14use MediaWiki\Revision\SlotRecord;
15
16/**
17 * @license GPL-2.0-or-later
18 */
19class EntitySchemaUpdateGuard {
20
21    private EntitySchemaConverter $schemaConverter;
22    private EntitySchemaDiffer $schemaDiffer;
23    private EntitySchemaPatcher $schemaPatcher;
24
25    public function __construct() {
26        $this->schemaConverter = new EntitySchemaConverter();
27        $this->schemaDiffer = new EntitySchemaDiffer();
28        $this->schemaPatcher = new EntitySchemaPatcher();
29    }
30
31    /**
32     * @param RevisionRecord $baseRevision The revision that the user’s data is based on.
33     * @param RevisionRecord $parentRevision The parent revision returned by the PageUpdater.
34     * @param callable $schemaUpdate Function accepting a FullArraySchemaData object,
35     * updating it with the user’s data.
36     * @return PersistenceEntitySchemaData|null The data that should be stored,
37     * or null if there is nothing to do.
38     * @throws EditConflict
39     */
40    public function guardSchemaUpdate(
41        RevisionRecord $baseRevision,
42        RevisionRecord $parentRevision,
43        callable $schemaUpdate
44    ): ?PersistenceEntitySchemaData {
45        $baseData = $this->schemaConverter->getFullArraySchemaData(
46            // @phan-suppress-next-line PhanUndeclaredMethod
47            $baseRevision->getContent( SlotRecord::MAIN )->getText()
48        );
49
50        $updateData = clone $baseData;
51        $schemaUpdate( $updateData );
52
53        $this->cleanupData( $baseData );
54        $this->cleanupData( $updateData );
55        $diff = $this->schemaDiffer->diffSchemas( $baseData, $updateData );
56
57        if ( $diff->isEmpty() ) {
58            return null;
59        }
60
61        if ( $baseRevision->getId() === $parentRevision->getId() ) {
62            return $this->array2persistence( $updateData );
63        }
64
65        $parentData = $this->schemaConverter->getFullArraySchemaData(
66            // @phan-suppress-next-line PhanUndeclaredMethod
67            $parentRevision->getContent( SlotRecord::MAIN )->getText()
68        );
69        try {
70            $patchedData = $this->schemaPatcher->patchSchema( $parentData, $diff );
71        } catch ( PatcherException $e ) {
72            throw new EditConflict( $e->getMessage(), $e->getCode(), $e );
73        }
74
75        return $this->array2persistence( $patchedData );
76    }
77
78    private function cleanupData( FullArrayEntitySchemaData $data ): void {
79        EntitySchemaCleaner::cleanupParameters(
80            $data->data['labels'],
81            $data->data['descriptions'],
82            $data->data['aliases'],
83            $data->data['schemaText']
84        );
85    }
86
87    // TODO this is very silly
88    private function array2persistence( FullArrayEntitySchemaData $arrayData ): PersistenceEntitySchemaData {
89        $persistenceData = new PersistenceEntitySchemaData();
90        $persistenceData->labels = $arrayData->data['labels'];
91        $persistenceData->descriptions = $arrayData->data['descriptions'];
92        $persistenceData->aliases = $arrayData->data['aliases'];
93        $persistenceData->schemaText = $arrayData->data['schemaText'];
94        return $persistenceData;
95    }
96
97}