server/src/app/Libraries/Mergers/CocoonAbstractRdfMerger.php
changeset 18 f2a40bbc27f6
child 19 eadaf0b8f02e
equal deleted inserted replaced
17:ac3dc090e987 18:f2a40bbc27f6
       
     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 }