app/resto/core/utils/RestoFeatureUtil.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/*
 * Copyright 2018 Jérôme Gasperi
 *
 * Licensed under the Apache License, version 2.0 (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

/**
 * resto feature manipulation
 */
class RestoFeatureUtil
{
    /*
     * Reference to resto context
     */
    private $context;

    /*
     * Reference to resto user
     */
    private $user;

    /*
     * Array of collections
     */
    private $collections = array();

    /**
     * Constructor
     *
     * @param RestoContext $context
     * @param RestoUser $user
     * @param array $collections
     */
    public function __construct($context, $user, $collections)
    {
        $this->context = $context;
        $this->user =$user;
        $this->collections = $collections;
    }

    /**
     *
     * Return a featureArray from an input rawFeatureArray.
     *
     * @param array $rawFeatureArray
     *
     */
    public function toFeatureArray($rawFeatureArray)
    {
        /*
         * No result - throw Not Found exception
         */
        if (!isset($rawFeatureArray) || !is_array($rawFeatureArray)) {
            RestoLogUtil::httpError(404);
        }

        /*
         * Retrieve collection from database
         */
        $collection = $this->collections[$rawFeatureArray['collection']] ?? null;
        if (!isset($collection)) {
            $collection = $this->context->keeper->getRestoCollection($rawFeatureArray['collection'], $this->user)->load();
            $this->collections[$rawFeatureArray['collection']] = $collection;
        }

        return $this->formatRawFeatureArray($rawFeatureArray, $collection);
    }

    /**
     * Return an array of featureArray from an input array of rawFeatureArray.
     *
     * @param array $rawFeatureArrayList
     * @return array
     */
    public function toFeatureArrayList($rawFeatureArrayList)
    {
        $featuresArray = array();
        for ($i = 0, $ii = count($rawFeatureArrayList); $i < $ii; $i++) {
            $featuresArray[] = $this->toFeatureArray($rawFeatureArrayList[$i]);
        }
        return $featuresArray;
    }

    /**
     *
     * PostgreSQL output columns are treated as string
     * thus they need to be converted to their true type
     *
     * @param Array $rawFeatureArray
     * @param RestoCollection $collection
     * @return array
     */
    private function formatRawFeatureArray($rawFeatureArray, $collection)
    {
        $self = $this->context->core['baseUrl'] . RestoUtil::replaceInTemplate(RestoRouter::ROUTE_TO_FEATURE, array(
            'collectionId' => $collection->id,
            'featureId' => $rawFeatureArray['id']
        ));
        $featureArray = array(
            'type' => 'Feature',
            'id' => $rawFeatureArray['id'],
            'geometry' => null,
            'properties' => array(),
            'collection' => $collection->id,
            'links' => array(
                array(
                    'rel' => 'self',
                    'type' => RestoUtil::$contentTypes['geojson'],
                    'href' => $self
                ),
                array(
                    'rel' => 'parent',
                    'type' => RestoUtil::$contentTypes['json'],
                    'title' => $collection->id,
                    'href' => $this->context->core['baseUrl'] . RestoUtil::replaceInTemplate(RestoRouter::ROUTE_TO_COLLECTION, array(
                        'collectionId' => $collection->id
                    ))
                ),
                array(
                    'rel' => 'collection',
                    'type' => RestoUtil::$contentTypes['json'],
                    'title' => $collection->id,
                    'href' => $this->context->core['baseUrl'] . RestoUtil::replaceInTemplate(RestoRouter::ROUTE_TO_COLLECTION, array(
                        'collectionId' => $collection->id
                    ))
                ),
                array(
                    'rel' => 'root',
                    'type' => RestoUtil::$contentTypes['json'],
                    'href' => $this->context->core['baseUrl']
                )
            ),
            'assets' => array(),
            'stac_version' => STAC::STAC_VERSION,
            'stac_extensions' => $collection->model->stacExtensions
        );

        /*
         * Handle SKOS relations
         */
        if (isset($this->context->addons['SOSA'])) {
            $featureArray['links'] = array_merge(
                $featureArray['links'],
                array(
                    array(
                        'rel' => 'child',
                        'type' => RestoUtil::$contentTypes['json'],
                        'href' => $self . '/relations/hasSample'
                    ),
                    array(
                        'rel' => 'isSampleOf',
                        'type' => RestoUtil::$contentTypes['json'],
                        'href' => $self . '/relations/isSampleOf'
                    )
                )
            );
        }

        foreach ($rawFeatureArray as $key => $value) {
            if (!isset($value)) {
                continue;
            }

            switch ($key) {
                case 'collection':
                    break;

                case 'completionDate':
                    $featureArray['properties']['end_datetime'] = $rawFeatureArray[$key];
                    break;

                case 'startDate':
                    if (isset($rawFeatureArray['completionDate'])) {
                        $featureArray['properties']['start_datetime'] = $rawFeatureArray[$key];
                    }
                    else {
                        $featureArray['properties']['datetime'] = $rawFeatureArray[$key];
                    }
                    break;

                case 'assets':
                case 'geometry':
                    $featureArray[$key] = json_decode($value, true);
                    break;

                case 'links':
                    $featureArray[$key] = array_merge($featureArray[$key], $this->getLinks(json_decode($value, true), $self));
                    break;

                case 'bbox4326':
                    $featureArray['bbox'] = RestoGeometryUtil::box2dTobbox($value);
                    break;

                case 'keywords':
                    $featureArray['properties']['resto:keywords'] = $this->addKeywordsHref(json_decode($value, true), $collection);
                    break;

                case 'liked':
                    $featureArray['properties'][$key] = $value === 't' ? true : false;
                    break;
                
                case 'centroid':
                    $featureArray['properties'][$key] = json_decode($value, true)['coordinates'];
                    break;
                
                case 'status':
                case 'visibility':
                case 'likes':
                case 'comments':
                    $featureArray['properties'][$key] = (integer) $value;
                    break;

                case 'hashtags':
                    $featureArray['properties'][$key] = explode(',', substr($value, 1, -1));
                    break;

                case 'metadata':
                    $metadata = json_decode($value, true);
                    if (isset($metadata)) {
                        foreach (array_keys($metadata) as $metadataKey) {
                            $featureArray['properties'][$metadataKey] = $metadata[$metadataKey];
                        }
                    }
                    break;

                default:
                    $featureArray['properties'][$key] = $value;
            }
        }

        // [STAC][1.0.0-rc.3] Add preview in rel
        if (isset($featureArray['assets']) && isset($featureArray['assets']['thumbnail'])) {
            $featureArray['links'][] = array(
                'rel' => 'preview',
                'type' => $featureArray['assets']['thumbnail']['type'],
                'href' => $featureArray['assets']['thumbnail']['href']
            );
        }

        // Add planet if not already set
        if (! isset($featureArray['properties']['ssys:targets']) || ! is_array($featureArray['properties']['ssys:targets'])) {
            $featureArray['properties']['ssys:targets'] = array($collection->getPlanet());
        }

        return $featureArray;
    }


    /**
     *
     * Add href to keywords
     *
     * @param array $keywords
     * @param RestoCollection $collection
     *
     * @return array
     */
    private function addKeywordsHref($keywords, $collection)
    {
        if (isset($keywords)) {
            foreach (array_keys($keywords) as $key) {
                $keywords[$key]['href'] = RestoUtil::updateUrl(
                    $this->context->core['baseUrl'] . RestoUtil::replaceInTemplate(
                        RestoRouter::ROUTE_TO_FEATURES,
                        array(
                            'collectionId' => $collection->id
                        )
                    ),
                    array(
                        $collection->model->searchFilters['language']['osKey'] => $this->context->lang,
                        $collection->model->searchFilters['searchTerms']['osKey'] => '#' . $keywords[$key]['id']
                    )
                );
            }
        }

        return $keywords;
    }

    /**
     * Add default links (i.e. self, parent and collection links) to feature links
     *
     * @param array $inputLinks
     * @return array
     */
    private function getLinks($inputLinks)
    {
        $links = array();

        for ($i = count($inputLinks); $i--;) {
            if (!in_array($inputLinks[$i]['rel'], array('self', 'parent', 'collection', 'root'))) {
                $links[] = $inputLinks[$i];
            }
        }

        return $links;
    }
}