|
1 <?php |
|
2 namespace CorpusParole\Libraries\Mergers; |
|
3 |
|
4 |
|
5 use EasyRdf\RdfNamespace; |
|
6 use EasyRdf\Graph; |
|
7 |
|
8 RdfNamespace::set('edm', 'http://www.europeana.eu/schemas/edm/'); |
|
9 RdfNamespace::set('ore', 'http://www.openarchives.org/ore/terms/'); |
|
10 RdfNamespace::set('crdo', 'http://crdo.risc.cnrs.fr/schemas/'); |
|
11 RdfNamespace::set('olac', 'http://www.language-archives.org/OLAC/1.1/'); |
|
12 RdfNamespace::set('skos', 'http://www.w3.org/2004/02/skos/core#'); |
|
13 |
|
14 abstract class CocoonAbstractRdfMerger implements RdfMerger { |
|
15 |
|
16 const ORIGIN_BASE = 0; |
|
17 const ORIGIN_SRC = 1; |
|
18 |
|
19 abstract protected function getTypeMergeMethodMap(); |
|
20 |
|
21 /** |
|
22 * Merge an Rdf Graph from one model to another |
|
23 * |
|
24 * @param EasyRdf\Graph $baseGraph The graph used as base for the merge |
|
25 * @param EasyRdf\Graph $srcGraph The source graph with the new triples to add |
|
26 * |
|
27 * @return EasyRdf\Graph The new merged graph |
|
28 */ |
|
29 function mergeGraph($baseGraph, $srcGraph) { |
|
30 |
|
31 $this->mergedArray = []; |
|
32 $this->resGraph = new Graph($baseGraph->getUri()); |
|
33 $this->bnodeMerge = []; |
|
34 $this->baseGraph = $baseGraph; |
|
35 $this->srcGraph = $srcGraph; |
|
36 |
|
37 |
|
38 $typeMergeMethodMap = $this->getTypeMergeMethodMap(); |
|
39 |
|
40 foreach ( $typeMergeMethodMap as $nodeType => $mergeMethod) { |
|
41 |
|
42 foreach($baseGraph->allOfType($nodeType) as $baseResource) { |
|
43 if($baseResource->isBNode()) { |
|
44 continue; |
|
45 } |
|
46 $this->mergedArray[$baseResource->getUri()] = $baseGraph->toRdfPhp()[$baseResource->getUri()]; |
|
47 } |
|
48 foreach($srcGraph->allOfType($nodeType) as $srcResource) { |
|
49 if($baseResource->isBNode()) { |
|
50 continue; |
|
51 } |
|
52 if(empty($baseGraph->propertyUris($srcResource->getUri()))) { |
|
53 $this->mergedArray[$srcResource->getUri()] = $srcGraph->toRdfPhp()[$srcResource->getUri()]; |
|
54 } |
|
55 else { |
|
56 $baseResource = $baseGraph->resource($srcResource->getUri()); |
|
57 $this->mergedArray[$srcResource->getUri()] = $baseGraph->toRdfPhp()[$baseResource->getUri()]; |
|
58 call_user_func(array($this, $mergeMethod), $baseResource, $srcResource); |
|
59 } |
|
60 } |
|
61 } |
|
62 |
|
63 // merge blank node |
|
64 reset($this->bnodeMerge); |
|
65 while(list($bnodeId, $bnodeDef) = each($this->bnodeMerge)) { |
|
66 |
|
67 $srcUrl = isset($bnodeDef['src_url'])?$bnodeDef['src_url']:null; |
|
68 $baseUrl = isset($bnodeDef['base_url'])?$bnodeDef['base_url']:null; |
|
69 |
|
70 if(is_null($srcUrl) && !is_null($baseUrl)) { |
|
71 $this->mergedArray[$bnodeId] = $this->copyResource($baseGraph->toRdfPhp()[$baseUrl],CocoonAbstractRdfMerger::ORIGIN_BASE); |
|
72 } |
|
73 elseif (is_null($baseUrl) && !is_null($srcUrl)) { |
|
74 $this->mergedArray[$bnodeId] = $this->copyResource($srcGraph->toRdfPhp()[$srcUrl],CocoonAbstractRdfMerger::ORIGIN_SRC); |
|
75 } |
|
76 elseif (!is_null($baseUrl) && !is_null($srcUrl)) { |
|
77 |
|
78 $baseResource = $baseGraph->resource($baseUrl); |
|
79 $srcResource = $srcGraph->resource($srcUrl); |
|
80 |
|
81 $mergeMethod = $typeMergeMethodMap[$baseResource->typeAsResource()->getUri()]; |
|
82 $this->mergedArray[$bnodeId] = []; |
|
83 |
|
84 call_user_func(array($this, $mergeMethod), $baseResource, $srcResource, $bnodeId); |
|
85 |
|
86 } |
|
87 |
|
88 } |
|
89 |
|
90 //echo "MERGED ARRAY:\n"; |
|
91 $this->resGraph->parse($this->mergedArray); |
|
92 return $this->resGraph; |
|
93 } |
|
94 |
|
95 /** |
|
96 * Copy a full resource node |
|
97 * |
|
98 */ |
|
99 protected function copyResource($origArray, $origin) { |
|
100 $resArray = []; |
|
101 foreach($origArray as $prop => $propValues) { |
|
102 $resArray[$prop] = $this->buildValueList($propValues, $origin); |
|
103 } |
|
104 return $resArray; |
|
105 } |
|
106 |
|
107 /** |
|
108 * Build a value list. replace the blank node reference. |
|
109 * @param $srcValues array The original values |
|
110 * @param $origin int values are 'ORIGIN_BASE' if bnode from base graph or 'ORIGIN_SRC' from source graph |
|
111 */ |
|
112 protected function buildValueList($srcValues, $origin) { |
|
113 $srcArrayProps = []; |
|
114 foreach ($srcValues as $propValue) { |
|
115 if(is_array($propValue) && array_key_exists('type', $propValue) && $propValue['type'] == 'bnode') { |
|
116 $newBNodeId = $this->resGraph->newBNodeId(); |
|
117 if($origin == CocoonAbstractRdfMerger::ORIGIN_SRC) { |
|
118 $this->bnodeMerge[$newBNodeId] = ['src_url' => $propValue['value'], 'base_url' => null]; |
|
119 } |
|
120 else { |
|
121 $this->bnodeMerge[$newBNodeId] = ['base_url' => $propValue['value'], 'src_url' => null]; |
|
122 } |
|
123 |
|
124 $propValue['value'] = $newBNodeId; |
|
125 } |
|
126 $srcArrayProps[] = $propValue; |
|
127 } |
|
128 return $srcArrayProps; |
|
129 } |
|
130 |
|
131 protected function mergePropertySingleValue($prop, &$targetArray, $baseArray, $srcArray) { |
|
132 |
|
133 if(isset($baseArray[$prop])) { |
|
134 $targetArray[$prop] = $this->buildValueList($baseArray[$prop], CocoonAbstractRdfMerger::ORIGIN_BASE); |
|
135 } |
|
136 elseif(isset($srcArray[$prop])) { |
|
137 $targetArray[$prop] = $this->buildValueList($srcArray[$prop], CocoonAbstractRdfMerger::ORIGIN_SRC); |
|
138 } |
|
139 } |
|
140 |
|
141 protected function mergePropertyMultiplevalue($prop, &$targetArray, $baseArray, $srcArray) { |
|
142 $propArray = $this->buildValueList(isset($baseArray[$prop])?$baseArray[$prop]:[], CocoonAbstractRdfMerger::ORIGIN_BASE); |
|
143 if(isset($srcArray[$prop])) { |
|
144 $mergedArray = array_merge($propArray, $this->buildValueList($srcArray[$prop], CocoonAbstractRdfMerger::ORIGIN_BASE)); |
|
145 //yes, this is real. Array_unique does not work on multidimentional arrays. Most work-around suggest the use of serialize to compare sub arrays... |
|
146 $propArray = array_values(array_intersect_key($mergedArray, array_unique(array_map('md5',array_map('serialize', $mergedArray))))); |
|
147 } |
|
148 |
|
149 if(!empty($propArray)) { |
|
150 $targetArray[$prop] = $propArray; |
|
151 } |
|
152 } |
|
153 |
|
154 protected function mergePropertySingleBNode($prop, &$targetArray, $baseArray, $srcArray) { |
|
155 |
|
156 $newBNodeId = $this->resGraph->newBNodeId(); |
|
157 |
|
158 $srcUrl = null; |
|
159 $baseUrl = null; |
|
160 |
|
161 // in src but not in base |
|
162 if(array_key_exists($prop, $baseArray) && |
|
163 !empty($baseArray[$prop]) && |
|
164 array_key_exists('type',$baseArray[$prop][0]) && |
|
165 array_key_exists('value',$baseArray[$prop][0]) && |
|
166 $baseArray[$prop][0]['type'] === 'bnode') { |
|
167 $baseUrl = $baseArray[$prop][0]['value']; |
|
168 } |
|
169 |
|
170 if(array_key_exists($prop, $srcArray) && |
|
171 !empty($srcArray[$prop]) && |
|
172 array_key_exists('type',$srcArray[$prop][0]) && |
|
173 array_key_exists('value',$srcArray[$prop][0]) && |
|
174 $srcArray[$prop][0]['type'] === 'bnode') { |
|
175 $srcUrl = $srcArray[$prop][0]['value']; |
|
176 } |
|
177 |
|
178 $this->bnodeMerge[$newBNodeId] = ['src_url' => $srcUrl, 'base_url' => $baseUrl]; |
|
179 |
|
180 $targetArray[$prop] = [ [ 'type' => 'bnode', 'value' => $newBNodeId], ]; |
|
181 |
|
182 } |
|
183 |
|
184 |
|
185 protected function mergeProperties($singleBNodeProperties, $singleProperties, &$targetArray, $baseRes, $srcRes) { |
|
186 $srcArray = $this->srcGraph->toRdfPhp()[$srcRes->getUri()]; |
|
187 $baseArray = $this->baseGraph->toRdfPhp()[$baseRes->getUri()]; |
|
188 foreach($srcRes->propertyUris() as $prop) { |
|
189 if(in_array($prop, $singleBNodeProperties)) { |
|
190 $this->mergePropertySingleBNode($prop, $targetArray, $baseArray, $srcArray); |
|
191 } |
|
192 elseif(in_array($prop, $singleProperties)) { |
|
193 $this->mergePropertySingleValue($prop, $targetArray, $baseArray, $srcArray); |
|
194 } |
|
195 else { |
|
196 $this->mergePropertyMultiplevalue($prop, $targetArray, $baseArray, $srcArray); |
|
197 } |
|
198 } |
|
199 } |
|
200 } |