diff --git a/local/config/libadmin/LinkedSwissbib.ini b/local/config/libadmin/LinkedSwissbib.ini new file mode 100644 index 0000000..e7ccad7 --- /dev/null +++ b/local/config/libadmin/LinkedSwissbib.ini @@ -0,0 +1,19 @@ + +[LINKED_DATA_REPOSITORIES] +REPOS=1 +SNL=1 +NEBIS=1 +RERO=1 +IDSBB=1 +IDSLU=1 +IDSSG=1 +IDSSG2=1 +ALEX=1 +SGBN=1 +SBT=1 +ABN=1 +BGR=1 +CCSA=1 +CHARCH=1 +LIBIB=1 + diff --git a/local/httpd-libadmin.conf b/local/httpd-libadmin.conf index a58258e..f27f57a 100644 --- a/local/httpd-libadmin.conf +++ b/local/httpd-libadmin.conf @@ -1,16 +1,21 @@ # Configuration for general VuFind base: Alias /libadmin /usr/local/vufind/libadmin/public - Order allow,deny - allow from all + + Order allow,deny + Allow from all + + + Require all granted + AllowOverride All AuthType Basic AuthName "Restricted Files" # (Following line optional) - AuthBasicProvider file - AuthUserFile /usr/local/vufind/libadmin/local/passwords - Require user libadmin +# AuthBasicProvider file +# AuthUserFile /usr/local/vufind/libadmin/local/passwords +# Require user libadmin # Uncomment the following lines, if you wish to use the Shibboleth authentication diff --git a/module/Libadmin/Module.php b/module/Libadmin/Module.php index f12554d..05aa72c 100644 --- a/module/Libadmin/Module.php +++ b/module/Libadmin/Module.php @@ -28,6 +28,25 @@ public function onBootStrap(MvcEvent $e) { $translator = $e->getApplication()->getServiceManager()->get('translator'); $translator->setLocale('de_DE'); /*->setFallbackLocale('en_US')*/ + + $app = $e->getApplication(); + $em = $app->getEventManager()->getSharedManager(); + $sm = $app->getServiceManager(); + + $em->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH, function($e) use ($sm) { + + $routeParams = $e->getRouteMatch()->getParams(); + if (array_key_exists('format',$routeParams) && strcmp($routeParams['format'],'formeta') == 0 ) { + $strategy = $sm->get('ViewFormetaStrategy'); + $view = $sm->get('ViewManager')->getView(); + $strategy->attach($view->getEventManager()); + } + + $t = ""; + + }); + + } diff --git a/module/Libadmin/config/module.config.php b/module/Libadmin/config/module.config.php index e0c72b7..10b5845 100644 --- a/module/Libadmin/config/module.config.php +++ b/module/Libadmin/config/module.config.php @@ -78,7 +78,7 @@ 'constraints' => array( 'system' => '[a-zA-Z][a-zA-Z0-9_-]*', 'view' => '[a-zA-Z][a-zA-Z0-9_-]*', - 'format' => '(xml|json|fake)' // add more formats here + 'format' => '(xml|json|fake|formeta)' // add more formats here ), 'defaults' => array( 'controller' => 'Libadmin\Controller\Api', @@ -94,17 +94,20 @@ 'libadmin' => __DIR__ . '/../view', ), 'strategies' => array( - 'ViewJsonStrategy' + 'ViewJsonStrategy','ViewFormetaStrategy' ) ), 'service_manager' => array( 'factories' => array( - 'Navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory' + 'Navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory', + 'ViewFormetaStrategy' => 'Libadmin\Services\View\ViewFormetaStrategyFactory', + 'FormetaRenderer' => 'Libadmin\Services\View\ViewFormetaRendererFactory' ), 'invokables' => array( 'export_system_vufind' => 'Libadmin\Export\System\Vufind', 'export_system_mapportal' => 'Libadmin\Export\System\MapPortal', + 'export_system_formeta' => 'Libadmin\Export\System\Formeta', ) ), @@ -155,7 +158,8 @@ ), 'libadmin' => array( - 'backlinksconfig' => 'local/config/libadmin/MapPortal.ini' + 'backlinksconfig' => 'local/config/libadmin/MapPortal.ini', + 'linkedswissbibconfig' => 'local/config/libadmin/LinkedSwissbib.ini' ), diff --git a/module/Libadmin/src/Libadmin/Export/System/Formeta.php b/module/Libadmin/src/Libadmin/Export/System/Formeta.php new file mode 100644 index 0000000..4763ed7 --- /dev/null +++ b/module/Libadmin/src/Libadmin/Export/System/Formeta.php @@ -0,0 +1,164 @@ + true, + 'data' => $this->getJsonPayloadData() + ); + } catch (\Exception $e) { + $data = array( + 'success' => false, + 'data' => array(), + 'error' => $e->getMessage() + ); + } + + + return new FormetaModel($data); + } + + /** + * Extract required data from institution + * + * @param Institution $institution + * @return Array + */ + protected function extractAllInstitutionData(Institution $institution, $groupCode) + { + $test = ""; + + return ['institution' => [ + + 'id' => $institution->getBib_code(), + 'sysDbId' => $institution->getId(), + 'sys_code' => $institution->getSys_code(), + 'label' => array( + 'de' => $institution->getLabel_de(), + 'fr' => $institution->getLabel_fr(), + 'it' => $institution->getLabel_it(), + 'en' => $institution->getLabel_en() + ), + 'name' => array( + 'de' => $institution->getName_de(), + 'fr' => $institution->getName_fr(), + 'it' => $institution->getName_it(), + 'en' => $institution->getName_en() + ), + 'url' => array( + 'de' => $institution->getUrl_de(), + 'fr' => $institution->getUrl_fr(), + 'it' => $institution->getUrl_it(), + 'en' => $institution->getUrl_en() + ), + 'address' => $institution->getAddress(), + 'zip' => $institution->getZip(), + 'city' => $institution->getCity(), + 'country' => $institution->getCountry(), + 'canton' => $institution->getCanton(), + 'website' => $institution->getWebsite(), + 'email' => $institution->getEmail(), + 'phone' => $institution->getPhone(), + 'skype' => $institution->getSkype(), + 'facebook' => $institution->getFacebook(), + 'coordinates' => $institution->getCoordinates(), + 'isil' => $institution->getIsil(), + 'notes' => $institution->getNotes(), + 'backlink' => $this->getBackLink($groupCode,$institution->getBib_code(),array()) + + ]]; + + } + + /** + * Get grouped institution data + * + * @return Array + */ + protected function getJsonPayloadData() + { + $data = array(); + $groups = $this->getGroups(); + //$extractInstitutionMethod = $this->getOption('all') == true ? 'extractAllInstitutionData' : 'extractInstitutionData'; + //the whole information should always be delivered to the client + $extractInstitutionMethod = 'extractAllInstitutionData'; + + + foreach ($groups as $group) { + + $repositoryForExportDefined = $this->configLinkedRepositories->LINKED_DATA_REPOSITORIES->offsetGet($group->code); + if (isset($repositoryForExportDefined) && $repositoryForExportDefined ) { + $groupData = array( + 'group' => $this->extractGroupData($group), + 'institutions' => array() + ); + + $institutions = $this->getGroupInstitutions($group); + + foreach ($institutions as $institution) { + $groupData['institutions'][] = $this->$extractInstitutionMethod($institution,$group->code); + } + + $data[] = $groupData; + + } + + + } + + return $data; + } + + /** + * @override + * @return void + */ + public function init() + { + + //http://localhost/libadmin/api/semanticweb/green.json?option[all]=true + //http://www.cambridgesemantics.com/semantic-university/getting-started + //documentation + //http://code.ohloh.net/project?pid=jZRKcGNwZOo&cid=9cCNLmy7F0s&fp=291221&mp=&projSelected=true + parent::init(); + + $config = $this->getServiceLocator()->get('config'); + $reader = new Ini(); + $this->configLinkedRepositories = new Config($reader->fromFile($config['libadmin']['linkedswissbibconfig'])); + + } + + +} + + diff --git a/module/Libadmin/src/Libadmin/Services/View/FormetaModel.php b/module/Libadmin/src/Libadmin/Services/View/FormetaModel.php new file mode 100644 index 0000000..f6d76a0 --- /dev/null +++ b/module/Libadmin/src/Libadmin/Services/View/FormetaModel.php @@ -0,0 +1,102 @@ +getVariables(); + if ($variables instanceof Traversable) { + $variables = ArrayUtils::iteratorToArray($variables); + } + + //return Json::encode($variables); + + $formetaString = null; + + foreach ($variables['data'] as $groupContainer) { + //$groupString = ""; + $groupString = $groupContainer['group']['code'] . ' {'; + foreach ($groupContainer['group'] as $groupKey => $groupValue) { + if (!is_array($groupValue)) { + //$groupString .= ' \'' . $groupKey . '\' : \'' . preg_replace(array('/\'/i'),array('\\'),$groupValue) . ' \','; + $groupString .= ' \'' . $groupKey . '\' : \'' . preg_replace(array('/\'/i','/\\\\V/i','/\\\\E/i','/d\\\\a/i','/d\\\\i/i'), + array('\\\'','E','d a','d\''),$groupValue) . ' \','; + } else { + $groupString .= $this->serializeEntity($groupKey,$groupValue) ; + } + + } + $formetaString .= $groupString; + + + $groupString = 'institutions {'; + + foreach ($groupContainer['institutions'] as $institutionsContainer) { + foreach ($institutionsContainer as $instKey => $instValue) { + if (!is_array($instValue)) { + + //$groupString .= ' \'' . $instKey . '\' : \'' . preg_replace(array('/\'/i'),array('\\'),$instValue) . ' \','; + $groupString .= ' \'' . $instKey . '\' : \'' . preg_replace(array('/\'/i','/\\\\V/i','/\\\\E/i','/d\\\\a/i','/d\\\\i/i'), + array('\\\'','V','E','d a','d\''),$instValue) . '\','; + } else { + + $groupString .= ' ' . $this->serializeEntity($instKey, $instValue) ; + + } + } + } + $formetaString .= $groupString; + + $formetaString .= '} '; // schliesse Institutions + $formetaString .= '}, '; + } + + return $formetaString; + + } + + + private function serializeEntity ($key, array $entity) { + + $localString = ' ' . $key . ' {'; + + foreach ($entity as $entityKey => $entityValue) + { + if (!is_array($entityValue)) { + //$localString .= '\'' . $entityKey . '\' : \'' . preg_replace(array('/\'/i'),array('\\'),$entityValue) . ' \','; + $localString .= '\'' . $entityKey . '\' : \'' . preg_replace(array('/\'/i','/\\\\V/i','/\\\\E/i','/d\\\\a/i','/d\\\\i/i'), + array('\\\'','V','E','d a','d\''),$entityValue) . '\','; + } else { + //$localString .= ' {' . $this->serializeEntity($entityKey,$entityValue) . ' }, '; + $localString .= ' ' . $this->serializeEntity($entityKey,$entityValue) . ', '; + } + //if (!is_array($groupLiteral)) + } + + $localString .= '}, '; + + return $localString; + + } +} diff --git a/module/Libadmin/src/Libadmin/Services/View/FormetaRenderer.php b/module/Libadmin/src/Libadmin/Services/View/FormetaRenderer.php new file mode 100644 index 0000000..e9a6c71 --- /dev/null +++ b/module/Libadmin/src/Libadmin/Services/View/FormetaRenderer.php @@ -0,0 +1,243 @@ +resolver = $resolver; + } + + /** + * Set flag indicating whether or not to merge unnamed children + * + * @param bool $mergeUnnamedChildren + * @return JsonRenderer + */ + public function setMergeUnnamedChildren($mergeUnnamedChildren) + { + $this->mergeUnnamedChildren = (bool) $mergeUnnamedChildren; + return $this; + } + + /** + * Set the JSONP callback function name + * + * @param string $callback + * @return JsonRenderer + */ + public function setJsonpCallback($callback) + { + $callback = (string) $callback; + if (!empty($callback)) { + $this->jsonpCallback = $callback; + } + return $this; + } + + /** + * Returns whether or not the jsonpCallback has been set + * + * @return bool + */ + public function hasJsonpCallback() + { + return (null !== $this->jsonpCallback); + } + + /** + * Should we merge unnamed children? + * + * @return bool + */ + public function mergeUnnamedChildren() + { + return $this->mergeUnnamedChildren; + } + + /** + * Renders values as JSON + * + * @todo Determine what use case exists for accepting both $nameOrModel and $values + * @param string|Model $nameOrModel The script/resource process, or a view model + * @param null|array|\ArrayAccess $values Values to use during rendering + * @throws Exception\DomainException + * @return string The script output. + */ + public function render($nameOrModel, $values = null) + { + // use case 1: View Models + // Serialize variables in view model + if ($nameOrModel instanceof Model) { + if ($nameOrModel instanceof FormetaModel) { + $values = $nameOrModel->serialize(); + } + + /* + if ($nameOrModel instanceof JsonModel) { + $children = $this->recurseModel($nameOrModel, false); + $this->injectChildren($nameOrModel, $children); + $values = $nameOrModel->serialize(); + } else { + $values = $this->recurseModel($nameOrModel); + $values = Json::encode($values); + } + + if ($this->hasJsonpCallback()) { + $values = $this->jsonpCallback . '(' . $values . ');'; + } + */ + return $values; + } + + // use case 2: $nameOrModel is populated, $values is not + // Serialize $nameOrModel + if (null === $values) { + if (!is_object($nameOrModel) || $nameOrModel instanceof JsonSerializable) { + $return = Json::encode($nameOrModel); + } elseif ($nameOrModel instanceof Traversable) { + $nameOrModel = ArrayUtils::iteratorToArray($nameOrModel); + $return = Json::encode($nameOrModel); + } else { + $return = Json::encode(get_object_vars($nameOrModel)); + } + + if ($this->hasJsonpCallback()) { + $return = $this->jsonpCallback . '(' . $return . ');'; + } + return $return; + } + + // use case 3: Both $nameOrModel and $values are populated + throw new Exception\DomainException(sprintf( + '%s: Do not know how to handle operation when both $nameOrModel and $values are populated', + __METHOD__ + )); + } + + /** + * Can this renderer render trees of view models? + * + * Yes. + * + * @return true + */ + public function canRenderTrees() + { + return true; + } + + /** + * Retrieve values from a model and recurse its children to build a data structure + * + * @param Model $model + * @param bool $mergeWithVariables Whether or not to merge children with + * the variables of the $model + * @return array + */ + protected function recurseModel(Model $model, $mergeWithVariables = true) + { + $values = array(); + if ($mergeWithVariables) { + $values = $model->getVariables(); + } + + if ($values instanceof Traversable) { + $values = ArrayUtils::iteratorToArray($values); + } + + if (!$model->hasChildren()) { + return $values; + } + + $mergeChildren = $this->mergeUnnamedChildren(); + foreach ($model as $child) { + $captureTo = $child->captureTo(); + if (!$captureTo && !$mergeChildren) { + // We don't want to do anything with this child + continue; + } + + $childValues = $this->recurseModel($child); + if ($captureTo) { + // Capturing to a specific key + // TODO please complete if append is true. must change old + // value to array and append to array? + $values[$captureTo] = $childValues; + } elseif ($mergeChildren) { + // Merging values with parent + $values = array_replace_recursive($values, $childValues); + } + } + return $values; + } + + /** + * Inject discovered child model values into parent model + * + * @todo detect collisions and decide whether to append and/or aggregate? + * @param Model $model + * @param array $children + */ + protected function injectChildren(Model $model, array $children) + { + foreach ($children as $child => $value) { + // TODO detect collisions and decide whether to append and/or aggregate? + $model->setVariable($child, $value); + } + } +} diff --git a/module/Libadmin/src/Libadmin/Services/View/FormetaStrategy.php b/module/Libadmin/src/Libadmin/Services/View/FormetaStrategy.php new file mode 100644 index 0000000..bc82375 --- /dev/null +++ b/module/Libadmin/src/Libadmin/Services/View/FormetaStrategy.php @@ -0,0 +1,134 @@ +renderer = $renderer; + } + + /** + * {@inheritDoc} + */ + public function attach(EventManagerInterface $events, $priority = 1) + { + $this->listeners[] = $events->attach(ViewEvent::EVENT_RENDERER, array($this, 'selectRenderer'), $priority); + $this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'injectResponse'), $priority); + } + + /** + * Set the content-type character set + * + * @param string $charset + * @return FormetaStrategy + */ + public function setCharset($charset) + { + $this->charset = (string) $charset; + return $this; + } + + /** + * Retrieve the current character set + * + * @return string + */ + public function getCharset() + { + return $this->charset; + } + + /** + * Detect if we should use the JsonRenderer based on model type and/or + * Accept header + * + * @param ViewEvent $e + * @return null|JsonRenderer + */ + public function selectRenderer(ViewEvent $e) + { + $model = $e->getModel(); + + if (!$model instanceof FormetaModel) { + // no JsonModel; do nothing + return; + } + + // JsonModel found + return $this->renderer; + } + + /** + * Inject the response with the JSON payload and appropriate Content-Type header + * + * @param ViewEvent $e + * @return void + */ + public function injectResponse(ViewEvent $e) + { + $renderer = $e->getRenderer(); + if ($renderer !== $this->renderer) { + // Discovered renderer is not ours; do nothing + return; + } + + $result = $e->getResult(); + if (!is_string($result)) { + // We don't have a string, and thus, no JSON + return; + } + + // Populate response + $response = $e->getResponse(); + $response->setContent($result); + $headers = $response->getHeaders(); + + if ($this->renderer->hasJsonpCallback()) { + $contentType = 'application/text'; + } else { + $contentType = 'application/text'; + } + + $contentType .= '; charset=' . $this->charset; + $headers->addHeaderLine('content-type', $contentType); + + if (in_array(strtoupper($this->charset), $this->multibyteCharsets)) { + $headers->addHeaderLine('content-transfer-encoding', 'BINARY'); + } + } +} diff --git a/module/Libadmin/src/Libadmin/Services/View/ViewFormetaRendererFactory.php b/module/Libadmin/src/Libadmin/Services/View/ViewFormetaRendererFactory.php new file mode 100644 index 0000000..82daca3 --- /dev/null +++ b/module/Libadmin/src/Libadmin/Services/View/ViewFormetaRendererFactory.php @@ -0,0 +1,21 @@ +get('FormetaRenderer'); + $formetastrategy = new FormetaStrategy($formetaRenderer); + return $formetastrategy; + } +}