tao-test/app/tao/helpers/form/class.GenerisFormFactory.php

396 lines
15 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2008-2010 (original work) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
* 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
*
*/
use oat\generis\model\GenerisRdf;
use oat\generis\model\OntologyRdf;
use oat\generis\model\OntologyRdfs;
use oat\generis\model\WidgetRdf;
use oat\tao\helpers\form\elements\TreeAware;
use oat\tao\helpers\form\elements\xhtml\SearchDropdown;
use oat\tao\helpers\form\elements\xhtml\SearchTextBox;
use oat\tao\helpers\form\ValidationRuleRegistry;
use oat\tao\model\TaoOntology;
use tao_helpers_form_elements_AsyncFile as AsyncFile;
use tao_helpers_form_elements_Authoring as Authoring;
use tao_helpers_form_elements_Calendar as Calendar;
use tao_helpers_form_elements_Checkbox as Checkbox;
use tao_helpers_form_elements_Combobox as ComboBox;
use tao_helpers_form_elements_GenerisAsyncFile as GenerisAsyncFile;
use tao_helpers_form_elements_Hiddenbox as HiddenBox;
use tao_helpers_form_elements_Htmlarea as HtmlArea;
use tao_helpers_form_elements_Radiobox as RadioBox;
use tao_helpers_form_elements_Textarea as TextArea;
use tao_helpers_form_elements_Textbox as TextBox;
use tao_helpers_form_elements_Treebox as TreeBox;
/**
* The GenerisFormFactory enables you to create Forms using rdf data and the
* api to provide it. You can give any node of your ontology and the factory
* create the appriopriate form. The Generis ontology (with the Widget Property)
* required to use it.
* Now only the xhtml rendering mode is implemented
*
* @access public
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
* @package tao
* @see core_kernel_classes_* packages
*/
class tao_helpers_form_GenerisFormFactory
{
// --- ASSOCIATIONS ---
// --- ATTRIBUTES ---
// --- OPERATIONS ---
/**
* Enable you to map an rdf property to a form element using the Widget
*
* @access public
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
*
* @param core_kernel_classes_Property $property
*
* @return tao_helpers_form_FormElement
*
* @throws common_Exception
* @throws common_exception_Error
* @throws core_kernel_persistence_Exception
*/
public static function elementMap(core_kernel_classes_Property $property): ?tao_helpers_form_FormElement
{
//create the element from the right widget
$property->feed();
$widgetResource = $property->getWidget();
//authoring widget is not used in standalone mode
if (
null === $widgetResource
|| $widgetResource->getUri() === Authoring::WIDGET_ID
&& tao_helpers_Context::check('STANDALONE_MODE')
) {
return null;
}
// horrible hack to fix file widget
if ($widgetResource->getUri() === AsyncFile::WIDGET_ID) {
$widgetResource = new core_kernel_classes_Resource(GenerisAsyncFile::WIDGET_ID);
}
$element = tao_helpers_form_FormFactory::getElementByWidget(tao_helpers_Uri::encode($property->getUri()), $widgetResource);
if (null === $element) {
return null;
}
if ($element->getWidget() !== $widgetResource->getUri()) {
common_Logger::w('Widget definition differs from implementation: ' . $element->getWidget() . ' != ' . $widgetResource->getUri());
return null;
}
//use the property label as element description
$propDesc = trim($property->getLabel()) !== ''
? $property->getLabel()
: str_replace(LOCAL_NAMESPACE, '', $property->getUri());
$element->setDescription($propDesc);
//multi elements use the property range as options
if (method_exists($element, 'setOptions')) {
$range = $property->getRange();
if ($range !== null) {
$options = [];
if ($element instanceof TreeAware) {
$sortedOptions = $element->rangeToTree(
$property->getUri() === OntologyRdfs::RDFS_RANGE ? new core_kernel_classes_Class(OntologyRdfs::RDFS_RESOURCE) : $range
);
} else {
foreach ($range->getInstances(true) as $rangeInstance) {
$level = $rangeInstance->getOnePropertyValue(new core_kernel_classes_Property(TaoOntology::PROPERTY_LIST_LEVEL));
if (is_null($level)) {
$options[tao_helpers_Uri::encode($rangeInstance->getUri())] = [tao_helpers_Uri::encode($rangeInstance->getUri()), $rangeInstance->getLabel()];
} else {
$level = ($level instanceof core_kernel_classes_Resource) ? $level->getUri() : (string)$level;
$options[$level] = [tao_helpers_Uri::encode($rangeInstance->getUri()), $rangeInstance->getLabel()];
}
}
ksort($options);
$sortedOptions = [];
foreach ($options as $id => $values) {
$sortedOptions[$values[0]] = $values[1];
}
//set the default value to an empty space
if (method_exists($element, 'setEmptyOption')) {
$element->setEmptyOption(' ');
}
}
//complete the options listing
$element->setOptions($sortedOptions);
}
}
foreach (ValidationRuleRegistry::getRegistry()->getValidators($property) as $validator) {
$element->addValidator($validator);
}
return $element;
}
/**
* Enable you to get the properties of a class.
* The advantage of this method is to limit the level of recusrivity in the
* It get the properties up to the defined top class
*
* @access public
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
* @param core_kernel_classes_Class $clazz
* @param core_kernel_classes_Class $topLevelClazz
* @return array
*/
public static function getClassProperties(
core_kernel_classes_Class $clazz,
core_kernel_classes_Class $topLevelClazz = null
): array {
if (null === $topLevelClazz) {
$topLevelClazz = new core_kernel_classes_Class(TaoOntology::CLASS_URI_OBJECT);
}
if ($clazz->getUri() === $topLevelClazz->getUri()) {
return $clazz->getProperties(false);
}
//determine the parent path
$parents = [];
$top = false;
do {
if (!isset($lastLevelParents)) {
$parentClasses = $clazz->getParentClasses(false);
} else {
$parentClasses = [];
foreach ($lastLevelParents as $parent) {
$parentClasses = array_merge($parentClasses, $parent->getParentClasses(false));
}
}
if (empty($parentClasses)) {
break;
}
$lastLevelParents = [];
foreach ($parentClasses as $parentClass) {
if ($parentClass->getUri() === OntologyRdfs::RDFS_CLASS) {
continue;
}
if ($parentClass->getUri() === $topLevelClazz->getUri()) {
$parents[$parentClass->getUri()] = $parentClass;
$top = true;
break;
}
$allParentClasses = $parentClass->getParentClasses(true);
if (array_key_exists($topLevelClazz->getUri(), $allParentClasses)) {
$parents[$parentClass->getUri()] = $parentClass;
}
$lastLevelParents[$parentClass->getUri()] = $parentClass;
}
} while (!$top);
$propertyChunks = [[]];
foreach ($parents as $parent) {
$propertyChunks[] = $parent->getProperties(false);
}
$propertyChunks[] = $clazz->getProperties(false);
return array_merge(...$propertyChunks);
}
/**
* get the default properties to add to every forms
*
* @access public
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
* @return array
*/
public static function getDefaultProperties(): array
{
return [
new core_kernel_classes_Property(OntologyRdfs::RDFS_LABEL)
];
}
/**
* Get the properties of the rdfs Property class
*
* @access public
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
* @param string mode
* @return array
*/
public static function getPropertyProperties($mode = 'simple'): array
{
$returnValue = [];
switch ($mode) {
case 'simple':
$defaultUris = [GenerisRdf::PROPERTY_IS_LG_DEPENDENT];
break;
case 'advanced':
default:
$defaultUris = [
OntologyRdfs::RDFS_LABEL,
WidgetRdf::PROPERTY_WIDGET,
OntologyRdfs::RDFS_RANGE,
GenerisRdf::PROPERTY_IS_LG_DEPENDENT
];
break;
}
$resourceClass = new core_kernel_classes_Class(OntologyRdf::RDF_PROPERTY);
foreach ($resourceClass->getProperties() as $property) {
if (in_array($property->getUri(), $defaultUris, true)) {
$returnValue[] = $property;
}
}
return $returnValue;
}
/**
* Return the map between the Property properties: range, widget, etc. to
* shortcuts for the simplePropertyEditor
*
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
*/
public static function getPropertyMap(): array
{
return [
'text' => [
'title' => __('Text - Short - Field'),
'widget' => TextBox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_LITERAL,
'multiple' => GenerisRdf::GENERIS_FALSE,
],
'longtext' => [
'title' => __('Text - Long - Box'),
'widget' => TextArea::WIDGET_ID,
'range' => OntologyRdfs::RDFS_LITERAL,
'multiple' => GenerisRdf::GENERIS_FALSE,
],
'html' => [
'title' => __('Text - Long - HTML editor'),
'widget' => HtmlArea::WIDGET_ID,
'range' => OntologyRdfs::RDFS_LITERAL,
'multiple' => GenerisRdf::GENERIS_FALSE,
],
'list' => [
'title' => __('List - Single choice - Radio button'),
'widget' => RadioBox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_RESOURCE,
'multiple' => GenerisRdf::GENERIS_FALSE,
'depends-on-property' => GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY,
],
'multiplenodetree' => [
'title' => __('Tree - Multiple node choice '),
'widget' => TreeBox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_RESOURCE,
'multiple' => GenerisRdf::GENERIS_TRUE,
],
'longlist' => [
'title' => __('List - Single choice - Drop down'),
'widget' => ComboBox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_RESOURCE,
'multiple' => GenerisRdf::GENERIS_FALSE,
'depends-on-property' => GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY,
],
'multilist' => [
'title' => __('List - Multiple choice - Check box'),
'widget' => Checkbox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_RESOURCE,
'multiple' => GenerisRdf::GENERIS_TRUE,
'depends-on-property' => GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY,
],
'multisearchlist' => [
'title' => __('List - Multiple choice - Search input'),
'widget' => SearchTextBox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_RESOURCE,
'multiple' => GenerisRdf::GENERIS_TRUE,
'depends-on-property' => GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY,
],
'singlesearchlist' => [
'title' => __('List - Single choice - Search input'),
'widget' => SearchDropdown::WIDGET_ID,
'range' => OntologyRdfs::RDFS_RESOURCE,
'multiple' => GenerisRdf::GENERIS_FALSE,
'depends-on-property' => GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY,
],
'calendar' => [
'title' => __('Calendar'),
'widget' => Calendar::WIDGET_ID,
'range' => OntologyRdfs::RDFS_LITERAL,
'multiple' => GenerisRdf::GENERIS_FALSE,
],
'password' => [
'title' => __('Password'),
'widget' => HiddenBox::WIDGET_ID,
'range' => OntologyRdfs::RDFS_LITERAL,
'multiple' => GenerisRdf::GENERIS_FALSE,
],
'file' => [
'title' => __('File'),
'widget' => AsyncFile::WIDGET_ID,
'range' => GenerisRdf::CLASS_GENERIS_FILE,
'multiple' => GenerisRdf::GENERIS_FALSE,
],
];
}
/**
* Short description of method extractTreeData
*
* @access public
* @author Bertrand Chevrier, <bertrand.chevrier@tudor.lu>
* @param array $data
* @return array
*/
public static function extractTreeData($data): array
{
$returnValue = [];
if (isset($data['data'])) {
$data = [$data];
}
foreach ($data as $node) {
$returnValue[$node['attributes']['id']] = $node['data'];
if (isset($node['children'])) {
$returnValue = array_merge($returnValue, self::extractTreeData($node['children']));
}
}
return $returnValue;
}
}