<?php declare(strict_types=1); namespace uib\ub\loadspeakr\modules; use ARC2; use Exception; use uib\ub\loadspeakr\Configuration; use uib\ub\loadspeakr\Convert; use uib\ub\loadspeakr\Endpoint; use uib\ub\loadspeakr\HTTPStatus; use uib\ub\loadspeakr\Logging; use uib\ub\loadspeakr\Utils; final class ServiceModule implements ModuleInterface { private Configuration $configuration; private Utils $utils; private string $basedir; private Endpoint $endpoints; private array $lodspk; public function __construct(Configuration $configuration, Utils $utils) { $this->configuration = $configuration; $this->utils = $utils; $this->basedir = $configuration->getConfigValue('conf', 'basedir'); $this->endpoints = $configuration->getConfigValue('bootstrap', 'endpoints'); } /** * Checking default components. * * @param $serviceName * @param $arguments * @param $extension * @param $conf * @param $lodspk */ private function checkComponents($serviceName, $arguments, $extension, $conf, $lodspk) { if (file_exists( $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/scaffold.ttl' )) { $subDir = $this->readScaffold( $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/scaffold.ttl', join("/", $arguments) ); $subDir .= '/'; $lodspk['model'] = $conf['home'] . $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/' . $subDir; $lodspk['view'] = $conf['view']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/' . $subDir . $extension . '.template'; } elseif (file_exists( $conf['home'] . $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName )) { $lodspk['model'] = $conf['home'] . $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/'; $lodspk['view'] = $conf['home'] . $conf['view']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/' . $extension . '.template'; } else { if (is_null($lodspk['model']) && is_null($lodspk['view'])) { //checking other components if (!empty($conf['components']['services']) && count($conf['components']['services']) > 0) { foreach ($conf['components']['services'] as $service) { $serviceArray = explode("/", $service); if ($serviceName == end($serviceArray)) { array_pop($serviceArray); $conf['service']['prefix'] = array_pop($serviceArray); $conf['model']['directory'] = join("/", $serviceArray); $conf['view']['directory'] = $conf['model']['directory']; if (file_exists( $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/scaffold.ttl' )) { $subDir = $this->readScaffold( $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/scaffold.ttl', join("/", $arguments) ); $subDir .= '/'; $lodspk['model'] = $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/' . $subDir; $lodspk['view'] = $conf['view']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/' . $subDir . $extension . '.template'; } elseif (file_exists( $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName )) { $lodspk['model'] = $conf['model']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/'; $lodspk['view'] = $conf['view']['directory'] . '/' . $conf['service']['prefix'] . '/' . $serviceName . '/' . $extension . '.template'; } } } } } } return ['conf' => $conf, 'lodspk' => $lodspk]; } public function match($uri) { $conf = $this->configuration->getConfigValues('conf'); $acceptContentType = $this->configuration->getConfigValue('bootstrap', 'acceptContentType'); $localUri = $this->configuration->getConfigValue('bootstrap', 'localUri'); $lodspk = $this->configuration->getConfigValue('bootstrap', 'lodspk'); $q = preg_replace('|^' . $conf['basedir'] . '|', '', $localUri); $qArr = explode('/', $q); if (sizeof($qArr) == 0) { return false; } $extension = Utils::getExtension($acceptContentType, $conf['http_accept']); $viewFile = null; $tokens = $qArr; $arguments = array(); while (sizeof($tokens) > 0) { $serviceName = join("%2F", $tokens); //Use .extension at the end of the service to force a particular content type $lastSegment = end($tokens); if (strpos($lastSegment, '.') > 0) { $aux = explode(".", $lastSegment); if (sizeof($aux) > 1) { $requestExtension = array_pop($aux); $contentTypes = $conf['http_accept'][$requestExtension]; if ($contentTypes != null) { $acceptContentType = $contentTypes[0]; $extension = $requestExtension; } } $serviceName = join(".", $aux); } $foundComponents = $this->checkComponents( $serviceName, $arguments, $extension, $conf, $this->configuration->getConfigValue('bootstrap', 'lodspk') ); $lodspk = $foundComponents["lodspk"]; $lodspk['serviceName'] = implode("/", $tokens); $lodspk['componentName'] = $lodspk['serviceName']; $modelFile = $foundComponents['lodspk']['model'] . $extension . '.queries'; if (file_exists($lodspk['model'] . $extension . '.queries')) { if (!file_exists($lodspk['view'])) { $viewFile = null; } else { $viewFile = $lodspk['view']; } $this->lodspk = $lodspk; return array($modelFile, $viewFile); } if (file_exists($lodspk['model'] . 'queries')) { $modelFile = $lodspk['model'] . 'queries'; if (!file_exists($lodspk['view'])) { $lodspk['resultRdf'] = true; $viewFile = null; } else { $viewFile = $lodspk['view']; } $this->lodspk = $lodspk; return array($modelFile, $viewFile); } if (file_exists($lodspk['model'])) { HTTPStatus::send406($uri); } array_unshift($arguments, array_pop($tokens)); } $this->lodspk = $lodspk; return false; } private function altUri(array $parameter, int $index) { $nsLocal = $this->configuration->getConfigValue('conf', 'ns')['local']; $altUri = Utils::curie2uri($parameter[$index]); return preg_replace("|^" . $this->basedir . "|", $nsLocal, $altUri); } public function execute($service) { $conf = $this->configuration->getConfigValues('conf'); $localUri = $this->configuration->getConfigValue('bootstrap', 'localUri'); $uri = $this->configuration->getConfigValue('bootstrap', 'uri'); $acceptContentType = $this->configuration->getConfigValue('bootstrap', 'acceptContentType'); $lodspk = $this->configuration->getConfigValue('bootstrap', 'lodspk'); $firstResults = $this->configuration->getConfigValue('bootstrap', 'firstResults'); $results = $this->configuration->getConfigValue('bootstrap', 'results'); $context = array(); $context['contentType'] = $acceptContentType; $params = $this->getParams($localUri); $extension = Utils::getExtension($acceptContentType, $conf['http_accept']); $args = array(); list($modelFile, $viewFile) = $service; try { $prefixHeader = array(); for ($i = 0; $i < sizeof($params); $i++) { if (Utils::mirror_external_uris($conf)) { $params[$i] = Utils::uri2curie($this->altUri($params, $i)); } } $segmentConnector = ""; for ($i = 0; $i < sizeof($params); $i++) { Utils::curie2uri($params[$i]); $auxPrefix = Utils::getPrefix($params[$i]); if ($auxPrefix['ns'] != null) { $prefixHeader[] = $auxPrefix; } $args["arg" . $i] = $params[$i]; $args["all"] .= $segmentConnector . $params[$i]; if ($segmentConnector == "") { $segmentConnector = "/"; } } $results['params'] = $params; $lodspk['home'] = $conf['basedir']; $lodspk['baseUrl'] = $conf['basedir']; $lodspk['module'] = 'service'; $lodspk['root'] = $conf['root']; $lodspk['contentType'] = $acceptContentType; $lodspk['ns'] = $conf['ns']; $lodspk['this']['value'] = $uri; $lodspk['this']['curie'] = Utils::uri2curie($uri); $lodspk['local']['value'] = $localUri; $lodspk['local']['curie'] = Utils::uri2curie($localUri); $lodspk['contentType'] = $acceptContentType; $lodspk['endpoint'] = $conf['endpoint']; $lodspk['type'] = $modelFile; $lodspk['header'] = $prefixHeader; $lodspk['args'] = $args; $lodspk['add_mirrored_uris'] = false; $lodspk['baseUrl'] = $conf['basedir']; $lodspk['this']['value'] = $uri; if ($viewFile == null) { $lodspk['transform_select_query'] = true; } Utils::queryFile($modelFile, $this->endpoints, $results, $firstResults); if (!$lodspk['resultRdf']) { $results = Utils::internalize($results); $firstAux = Utils::getfirstResults($results); if (is_array($results)) { $resultsObj = Convert::array_to_object($results); $results = $resultsObj; } else { $resultsObj = $results; } $lodspk['firstResults'] = Convert::array_to_object($firstAux); } else { $resultsObj = $results; } Utils::processDocument($viewFile, $lodspk, $results); } catch (Exception $ex) { echo $ex->getMessage(); if ($conf['debug']) { Logging::log($ex->getMessage(), E_ERROR); } HTTPStatus::send500($uri); } } protected function getParams($uri) { $count = 1; $functionAndParams = explode('/', str_replace($this->basedir . $this->lodspk['serviceName'], '', $uri, $count)); if (sizeof($functionAndParams) > 1) { array_shift($functionAndParams); return $functionAndParams; } return array(null); } protected function readScaffold($scaffold, $serviceArgs) { $parser = ARC2::getTurtleParser(); $parser->parse($scaffold); $triples = $parser->getTriples(); $aux = Utils::filterTriples( $triples, array(null, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://lodspeakr.org/vocab/ScaffoldedService") ); $scaffoldUri = $aux[0][0]; $aux = Utils::filterTriples($triples, array($scaffoldUri, "http://lodspeakr.org/vocab/scaffold", null)); foreach ($aux as $r) { $patterns = Utils::filterTriples($triples, array($r[2], "http://lodspeakr.org/vocab/uriPattern", null)); $pattern = stripcslashes($patterns[0][2]); if (preg_match("|$pattern|", $serviceArgs) > 0) { $patternDir = Utils::filterTriples( $triples, array($r[2], "http://lodspeakr.org/vocab/subComponent", null) ); return $patternDir[0][2]; } } return ""; } }