defaultData(); $myAdderFormContainer = new tao_actions_form_List(); $myForm = $myAdderFormContainer->getForm(); if ($myForm->isSubmited()) { if ($myForm->isValid()) { $values = $myForm->getValues(); $newList = $this->getListService()->createList($values['label']); $i = 0; while ($i < $values['size']) { $this->getListService()->createListElement($newList, __('element') . ' ' . ($i + 1)); $i++; } } } else { $myForm->getElement('label')->setValue(__('List') . ' ' . (count($this->getListService()->getLists()) + 1)); } $this->setData('form', $myForm->render()); $this->setData('lists', $this->getListData()); $this->setView('Lists/index.tpl'); } /** * @param ValueCollectionService $valueCollectionService * @param RemoteSource $remoteSource * * @throws ExtensionException * @throws core_kernel_persistence_Exception */ public function remote( ValueCollectionService $valueCollectionService, RemoteSource $remoteSource ) { tao_helpers_Scriptloader::addCssFile(Template::css('lists.css', 'tao')); $this->defaultData(); $remoteListFormFactory = new tao_actions_form_RemoteList( [], [ tao_actions_form_RemoteList::IS_LISTS_DEPENDENCY_ENABLED => $this->isListsDependencyEnabled(), ] ); $remoteListForm = $remoteListFormFactory->getForm(); if ($remoteListForm === null) { throw new RuntimeException('Impossible to create remote sourced list form'); } if ($remoteListForm->isSubmited()) { if ($remoteListForm->isValid()) { $values = $remoteListForm->getValues(); $newList = $this->createList($values); try { $this->sync($valueCollectionService, $remoteSource, $newList); } catch (ValueConflictException $exception) { $this->returnError( $exception->getMessage() . __(' Probably given list was already imported.') ); return; } catch (RuntimeException $exception) { throw $exception; } finally { if (isset($exception)) { $this->removeList(tao_helpers_Uri::encode($newList->getUri())); } } } } else { $newListLabel = __('List') . ' ' . (count($this->getListService()->getLists()) + 1); $remoteListForm->getElement(tao_actions_form_RemoteList::FIELD_NAME)->setValue($newListLabel); } $this->setData('form', $remoteListForm->render()); $this->setData('lists', $this->getListData(true)); $this->setView('RemoteLists/index.tpl'); } /** * @param ValueCollectionService $valueCollectionService * @param RemoteSource $remoteSource * * @throws common_exception_BadRequest */ public function reloadRemoteList(ValueCollectionService $valueCollectionService, RemoteSource $remoteSource): void { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $saved = false; $uri = $_POST['uri'] ?? null; if (null !== $uri) { $decodedUri = tao_helpers_Uri::decode($uri); $this->sync( $valueCollectionService, $remoteSource, $this->getListService()->getList($decodedUri) ); $saved = true; } $this->returnJson(['saved' => $saved]); } private function createList(array $values): RdfClass { $class = $this->getListService()->createList($values[tao_actions_form_RemoteList::FIELD_NAME]); $propertyType = new RdfProperty(CollectionType::TYPE_PROPERTY); $propertyRemote = new RdfProperty((string) CollectionType::remote()); $class->setPropertyValue($propertyType, $propertyRemote); $propertySource = new RdfProperty(RemoteSourcedListOntology::PROPERTY_SOURCE_URI); $class->setPropertyValue($propertySource, $values[tao_actions_form_RemoteList::FIELD_SOURCE_URL]); $propertySource = new RdfProperty(RemoteSourcedListOntology::PROPERTY_ITEM_LABEL_PATH); $class->setPropertyValue($propertySource, $values[tao_actions_form_RemoteList::FIELD_ITEM_LABEL_PATH]); $propertySource = new RdfProperty(RemoteSourcedListOntology::PROPERTY_ITEM_URI_PATH); $class->setPropertyValue($propertySource, $values[tao_actions_form_RemoteList::FIELD_ITEM_URI_PATH]); if ($this->isListsDependencyEnabled()) { $propertySource = new RdfProperty(RemoteSourcedListOntology::PROPERTY_DEPENDENCY_ITEM_URI_PATH); $class->setPropertyValue( $propertySource, $values[tao_actions_form_RemoteList::FIELD_DEPENDENCY_ITEM_URI_PATH] ); } return $class; } /** * @param ValueCollectionService $valueCollectionService * @param RemoteSource $remoteSource * @param RdfClass $collectionClass * * @throws core_kernel_persistence_Exception */ public function sync( ValueCollectionService $valueCollectionService, RemoteSource $remoteSource, RdfClass $collectionClass ): void { $context = $this->createRemoteSourceContext($collectionClass); $collection = new ValueCollection( $collectionClass->getUri(), ...iterator_to_array($remoteSource->fetchByContext($context)) ); $result = $valueCollectionService->persist($collection); if (!$result) { throw new RuntimeException('Sync was not successful'); } } /** * Returns all lists with all values for all lists * * @param bool $showRemoteLists * * @return array * @throws core_kernel_persistence_Exception */ private function getListData(bool $showRemoteLists = false): array { $listService = $this->getListService(); $lists = []; foreach ($listService->getLists() as $listClass) { if ($listService->isRemote($listClass) !== $showRemoteLists) { continue; } $elements = []; foreach ( $listService->getListElements( $listClass, true, $showRemoteLists ? self::REMOTE_LIST_PREVIEW_LIMIT : 0 ) as $index => $listElement ) { $elements[$index] = [ 'uri' => tao_helpers_Uri::encode($listElement->getUri()), 'label' => $listElement->getLabel() ]; ksort($elements); } if ($showRemoteLists && count($elements) === self::REMOTE_LIST_PREVIEW_LIMIT) { $elements[] = [ 'uri' => '', 'label' => '...', ]; } $lists[] = [ 'uri' => tao_helpers_Uri::encode($listClass->getUri()), 'label' => $listClass->getLabel(), // The Language list should not be editable. // @todo Make two different kind of lists: system list that are not editable and usual list. 'editable' => $listClass->isSubClassOf($this->getClass(TaoOntology::CLASS_URI_LIST)) && $listClass->getUri() !== tao_models_classes_LanguageService::CLASS_URI_LANGUAGES, 'elements' => $elements ]; } return $lists; } /** * get the JSON data to populate the tree widget * * @throws \common_exception_Error * @throws common_exception_BadRequest */ public function getListsData() { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $data = []; foreach ($this->getListService()->getLists() as $listClass) { $data[] = $this->getListService()->toTree($listClass); } $this->returnJson([ 'data' => __('Lists'), 'attributes' => ['class' => 'node-root'], 'children' => $data, 'state' => 'open' ]); } /** * get the elements in JSON of the list in parameter * @throws common_exception_BadRequest * @return void */ public function getListElements() { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $data = []; if ($this->hasRequestParameter('listUri')) { $list = $this->getListService()->getList(tao_helpers_Uri::decode($this->getRequestParameter('listUri'))); if (!is_null($list)) { $isRemote = $this->getListService()->isRemote($list); $limit = $isRemote ? self::REMOTE_LIST_PREVIEW_LIMIT : 0; foreach ($this->getListService()->getListELements($list, true, $limit) as $listElement) { $data[tao_helpers_Uri::encode($listElement->getUri())] = $listElement->getLabel(); } if ($isRemote && count($data) === self::REMOTE_LIST_PREVIEW_LIMIT) { $data[''] = '...'; } } } $this->returnJson($data); } /** * Save a list and it's elements * * @param ValueCollectionService $valueCollectionService * * @return void * * @throws common_exception_BadRequest */ public function saveLists(ValueCollectionService $valueCollectionService): void { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } if (!$this->hasRequestParameter('uri')) { $this->returnJson(['saved' => false]); return; } $listClass = $this->getListService()->getList(tao_helpers_Uri::decode($this->getRequestParameter('uri'))); if (null === $listClass) { $this->returnJson(['saved' => false]); return; } // use $_POST instead of getRequestParameters to prevent html encoding $payload = $_POST; unset($payload['uri']); if (isset($payload['label'])) { $listClass->setLabel($payload['label']); unset($payload['label']); } $elements = $valueCollectionService->findAll( new ValueCollectionSearchInput( (new ValueCollectionSearchRequest()) ->setValueCollectionUri($listClass->getUri()) ) ); foreach ($payload as $key => $value) { if (preg_match('/^list-element_/', $key)) { $encodedUri = preg_replace('/^list-element_[0-9]+_/', '', $key); $uri = tao_helpers_Uri::decode($encodedUri); $newUriValue = trim($payload["uri_$key"] ?? ''); $element = $elements->extractValueByUri($uri); if (null === $element) { $elements->addValue(new Value(null, $newUriValue, $value)); } else { $element->setLabel($value); if ($newUriValue) { $element->setUri($newUriValue); } } } } try { $this->returnJson(['saved' => $valueCollectionService->persist($elements)]); } catch (ValueConflictException $exception) { $this->returnJson(['saved' => false, 'errors' => [__('The list should contain unique URIs')]]); } } /** * Create a list or a list element * @throws common_exception_BadRequest * @return void */ public function create() { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $response = []; if ($this->getRequestParameter('classUri')) { if ($this->getRequestParameter('type') === 'class' && $this->getRequestParameter('classUri') ==='root') { $listClass = $this->getListService()->createList(); if (!is_null($listClass)) { $response['label'] = $listClass->getLabel(); $response['uri'] = tao_helpers_Uri::encode($listClass->getUri()); } } if ($this->getRequestParameter('type') === 'instance') { $listClass = $this->getListService()->getList(tao_helpers_Uri::decode($this->getRequestParameter('classUri'))); if (!is_null($listClass)) { $listElt = $this->getListService()->createListElement($listClass); if (!is_null($listElt)) { $response['label'] = $listElt->getLabel(); $response['uri'] = tao_helpers_Uri::encode($listElt->getUri()); } } } } $this->returnJson($response); } /** * Rename a list node: change the label of a resource * Render the json response with the renamed status * @throws common_exception_BadRequest * @return void */ public function rename() { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $data = ['renamed' => false]; if ($this->hasRequestParameter('uri') && $this->hasRequestParameter('newName')) { if ($this->hasRequestParameter('classUri')) { $listClass = $this->getListService()->getList(tao_helpers_Uri::decode($this->getRequestParameter('classUri'))); $listElt = $this->getListService()->getListElement($listClass, tao_helpers_Uri::decode($this->getRequestParameter('uri'))); if (!is_null($listElt)) { $listElt->setLabel($this->getRequestParameter('newName')); if ($listElt->getLabel() == $this->getRequestParameter('newName')) { $data['renamed'] = true; } } } else { $listClass = $this->getListService()->getList(tao_helpers_Uri::decode($this->getRequestParameter('uri'))); if (!is_null($listClass)) { $listClass->setLabel($this->getRequestParameter('newName')); if ($listClass->getLabel() == $this->getRequestParameter('newName')) { $data['renamed'] = true; } } } } $this->returnJson($data); } /** * Remove the list in parameter * * @param string|null $uri * * @return void * @throws common_exception_BadRequest */ public function removeList(?string $uri = null): void { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $deleted = false; if (null !== $uri) { $decodedUri = tao_helpers_Uri::decode($uri); $deleted = $this->getListService()->removeList( $this->getListService()->getList($decodedUri) ); } $this->returnJson(['deleted' => $deleted]); } /** * Remove the list element in parameter * @throws common_exception_BadRequest * @return void */ public function removeListElement() { if (!$this->isXmlHttpRequest()) { throw new common_exception_BadRequest('wrong request mode'); } $deleted = false; if ($this->hasRequestParameter('uri')) { $deleted = $this->getListService()->removeListElement( $this->getResource(tao_helpers_Uri::decode($this->getRequestParameter('uri'))) ); } $this->returnJson(['deleted' => $deleted]); } /** * @return ListService */ protected function getListService() { return ListService::singleton(); } private function createRemoteSourceContext(RdfClass $collectionClass): RemoteSourceContext { $sourceUrl = (string) $collectionClass->getOnePropertyValue( $collectionClass->getProperty(RemoteSourcedListOntology::PROPERTY_SOURCE_URI) ); $uriPath = (string) $collectionClass->getOnePropertyValue( $collectionClass->getProperty(RemoteSourcedListOntology::PROPERTY_ITEM_URI_PATH) ); $labelPath = (string) $collectionClass->getOnePropertyValue( $collectionClass->getProperty(RemoteSourcedListOntology::PROPERTY_ITEM_LABEL_PATH) ); $parameters = [ RemoteSourceContext::PARAM_SOURCE_URL => $sourceUrl, RemoteSourceContext::PARAM_URI_PATH => $uriPath, RemoteSourceContext::PARAM_LABEL_PATH => $labelPath, RemoteSourceContext::PARAM_PARSER => 'jsonpath', ]; if ($this->isListsDependencyEnabled()) { $dependencyUriPath = (string) $collectionClass->getOnePropertyValue( $collectionClass->getProperty(RemoteSourcedListOntology::PROPERTY_DEPENDENCY_ITEM_URI_PATH) ); $parameters[RemoteSourceContext::PARAM_DEPENDENCY_URI_PATH] = $dependencyUriPath; } return new RemoteSourceContext($parameters); } private function isListsDependencyEnabled(): bool { if (!isset($this->isListsDependencyEnabled)) { $this->isListsDependencyEnabled = $this->getFeatureFlagChecker()->isEnabled( FeatureFlagCheckerInterface::FEATURE_FLAG_LISTS_DEPENDENCY_ENABLED ); } return $this->isListsDependencyEnabled; } private function getFeatureFlagChecker(): FeatureFlagCheckerInterface { return $this->getServiceLocator()->get(FeatureFlagChecker::class); } }