diff --git a/common/oatbox/user/UserLanguageService.php b/common/oatbox/user/UserLanguageService.php index 72d67e22a..aaf7d225d 100644 --- a/common/oatbox/user/UserLanguageService.php +++ b/common/oatbox/user/UserLanguageService.php @@ -29,6 +29,9 @@ class UserLanguageService extends ConfigurableService implements UserLanguageSer public const OPTION_LOCK_DATA_LANGUAGE = 'lock_data_language'; public const OPTION_AUTHORING_LANGUAGE = 'authoring_language'; + /** @var ?string */ + private $customInterfaceLanguage; + /** * {@inheritDoc} * @see \oat\oatbox\user\UserLanguageServiceInterface::getDefaultLanguage() @@ -56,6 +59,10 @@ public function getDataLanguage(User $user) */ public function getInterfaceLanguage(User $user) { + if (!empty($this->customInterfaceLanguage)) { + return $this->customInterfaceLanguage; + } + $lang = $user->getPropertyValues(GenerisRdf::PROPERTY_USER_UILG); return empty($lang) ? $this->getDefaultLanguage() : (string)current($lang); } @@ -72,4 +79,12 @@ public function getAuthoringLanguage(): string { return $this->getOption(self::OPTION_AUTHORING_LANGUAGE, $this->getDefaultLanguage()); } + + /** + * @inheritdoc + */ + public function setCustomInterfaceLanguage(?string $customInterfaceLanguage): void + { + $this->customInterfaceLanguage = $customInterfaceLanguage; + } } diff --git a/common/oatbox/user/UserLanguageServiceInterface.php b/common/oatbox/user/UserLanguageServiceInterface.php index 8e3949eab..81c948dd0 100644 --- a/common/oatbox/user/UserLanguageServiceInterface.php +++ b/common/oatbox/user/UserLanguageServiceInterface.php @@ -52,4 +52,12 @@ public function getInterfaceLanguage(User $user); * @return boolean */ public function isDataLanguageEnabled(); + + /** + * When a custom interface language is set, it overrides the interface language retrieved in the getInterfaceLanguage + * method. + * + * @param ?string $customInterfaceLanguage + */ + public function setCustomInterfaceLanguage(?string $customInterfaceLanguage): void; } diff --git a/common/session/class.BasicSession.php b/common/session/class.BasicSession.php index 4396b3af4..f1df3a6eb 100644 --- a/common/session/class.BasicSession.php +++ b/common/session/class.BasicSession.php @@ -15,7 +15,7 @@ * 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) 2017 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); + * Copyright (c) 2017-2021 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); * */ @@ -142,7 +142,20 @@ public function getDataLanguage() */ public function getInterfaceLanguage() { - return $this->getServiceLocator()->get(UserLanguageServiceInterface::class)->getInterfaceLanguage($this->getUser()); + /** @var PHPSession $session */ + $session = PHPSession::singleton(); + + /** @var UserLanguageServiceInterface $userLanguageService */ + $userLanguageService = $this->getServiceLocator()->get(UserLanguageServiceInterface::class); + + if ($session->hasAttribute('overrideInterfaceLanguage')) { + $userLanguageService->setCustomInterfaceLanguage($session->getAttribute('overrideInterfaceLanguage')); + } else { + // Just to be sure the custom interface language is removed when the session attribute is gone + $userLanguageService->setCustomInterfaceLanguage(null); + } + + return $userLanguageService->getInterfaceLanguage($this->getUser()); } /** diff --git a/core/GenerisRdf.php b/core/GenerisRdf.php index b58f16e4f..422412e48 100644 --- a/core/GenerisRdf.php +++ b/core/GenerisRdf.php @@ -60,6 +60,7 @@ interface GenerisRdf public const PROPERTY_MASK_SUBJECT = 'http://www.tao.lu/Ontologies/generis.rdf#MaskSubject'; public const PROPERTY_MASK_PREDICATE = 'http://www.tao.lu/Ontologies/generis.rdf#MaskPredicate'; public const PROPERTY_MASK_OBJECT = 'http://www.tao.lu/Ontologies/generis.rdf#MaskObject'; + public const PROPERTY_DEPENDS_ON_PROPERTY = 'http://www.tao.lu/Ontologies/generis.rdf#DependsOnProperty'; //@deprecated use UserRdf::CLASS_URI public const CLASS_GENERIS_USER = 'http://www.tao.lu/Ontologies/generis.rdf#User'; //@deprecated use UserRdf::PROPERTY_LOGIN diff --git a/core/kernel/classes/class.Property.php b/core/kernel/classes/class.Property.php index 71638898d..f6c5e6c16 100644 --- a/core/kernel/classes/class.Property.php +++ b/core/kernel/classes/class.Property.php @@ -21,10 +21,12 @@ * */ -use oat\generis\model\data\ModelManager; +declare(strict_types=1); + +use oat\generis\model\WidgetRdf; use oat\generis\model\GenerisRdf; use oat\generis\model\OntologyRdfs; -use oat\generis\model\WidgetRdf; +use oat\generis\model\resource\DependsOnPropertyCollection; /** * uriProperty must be a valid property otherwis return false, add this as a @@ -88,6 +90,9 @@ class core_kernel_classes_Property extends core_kernel_classes_Resource */ public $multiple = false; + /** @var DependsOnPropertyCollection */ + private $dependsOnPropertyCollection; + // --- OPERATIONS --- /** * @return core_kernel_persistence_PropertyInterface @@ -96,7 +101,7 @@ private function getImplementation() { return $this->getModel()->getRdfsInterface()->getPropertyImplementation(); } - + /** * constructor @@ -109,10 +114,11 @@ private function getImplementation() */ public function __construct($uri, $debug = '') { - parent::__construct($uri, $debug); + $this->lgDependent = null; $this->multiple = null; + $this->dependsOnPropertyCollection = new DependsOnPropertyCollection(); } /** @@ -145,7 +151,7 @@ public function getDomain() } } $returnValue = $this->domain; - + return $returnValue; } @@ -161,7 +167,7 @@ public function getDomain() public function setDomain(core_kernel_classes_Class $class) { $returnValue = (bool) false; - + if (!is_null($class)) { foreach ($this->getDomain()->getIterator() as $domainClass) { if ($class->equals($domainClass)) { @@ -190,7 +196,7 @@ public function setDomain(core_kernel_classes_Class $class) public function getRange() { $returnValue = null; - + if (is_null($this->range)) { $rangeProperty = $this->getProperty(OntologyRdfs::RDFS_RANGE); $rangeValues = $this->getPropertyValues($rangeProperty); @@ -222,6 +228,37 @@ public function setRange(core_kernel_classes_Class $class) return (bool) $returnValue; } + /** + * @TODO Improve getter + */ + public function getDependsOnPropertyCollection(): DependsOnPropertyCollection + { + $dependsOnProperty = $this->getProperty(GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY); + $dependsOnPropertyValues = $this->getPropertyValues($dependsOnProperty); + + foreach ($dependsOnPropertyValues as $dependsOnPropertyValue) { + if ($dependsOnPropertyValue !== GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY) { + $this->dependsOnPropertyCollection->append( + $this->getProperty($dependsOnPropertyValue) + ); + } + } + + return $this->dependsOnPropertyCollection; + } + + /** + * @TODO Improve setter + */ + public function setDependsOnPropertyCollection(DependsOnPropertyCollection $dependsOnPropertyCollection): void + { + foreach ($dependsOnPropertyCollection as $dependsOnProperty) { + $this->getImplementation()->setDependsOnProperty($this, $dependsOnProperty); + } + + $this->dependsOnPropertyCollection = $dependsOnPropertyCollection; + } + /** * Get the Property object corresponding to the widget of this Property. * @@ -235,7 +272,7 @@ public function getWidget() if ($this->widget === false) { $this->widget = $this->getOnePropertyValue($this->getProperty(WidgetRdf::PROPERTY_WIDGET)); } - + return $this->widget; } @@ -282,7 +319,7 @@ public function isMultiple() if (is_null($this->multiple)) { $multipleProperty = $this->getProperty(GenerisRdf::PROPERTY_MULTIPLE); $multiple = $this->getOnePropertyValue($multipleProperty); - + if (is_null($multiple)) { $returnValue = false; } else { @@ -290,7 +327,7 @@ public function isMultiple() } $this->multiple = $returnValue; } - + $returnValue = $this->multiple; return (bool) $returnValue; } @@ -306,7 +343,7 @@ public function isMultiple() */ public function setMultiple($isMultiple) { - + $this->getImplementation()->setMultiple($this, $isMultiple); $this->multiple = $isMultiple; } diff --git a/core/kernel/persistence/interface.PropertyInterface.php b/core/kernel/persistence/interface.PropertyInterface.php index a5f3261c1..4c5e8d079 100644 --- a/core/kernel/persistence/interface.PropertyInterface.php +++ b/core/kernel/persistence/interface.PropertyInterface.php @@ -30,8 +30,8 @@ interface core_kernel_persistence_PropertyInterface { - - + + /** * Short description of method isLgDependent * @@ -41,7 +41,7 @@ interface core_kernel_persistence_PropertyInterface * @return boolean */ public function isLgDependent(core_kernel_classes_Resource $resource); - + /** * Short description of method isMultiple * @@ -51,7 +51,7 @@ public function isLgDependent(core_kernel_classes_Resource $resource); * @return boolean */ public function isMultiple(core_kernel_classes_Resource $resource); - + /** * Short description of method getRange * @@ -61,7 +61,7 @@ public function isMultiple(core_kernel_classes_Resource $resource); * @return core_kernel_classes_Class */ public function getRange(core_kernel_classes_Resource $resource); - + /** * Short description of method delete * @@ -72,7 +72,7 @@ public function getRange(core_kernel_classes_Resource $resource); * @return boolean */ public function delete(core_kernel_classes_Resource $resource, $deleteReference = false); - + /** * Short description of method setRange * @@ -83,7 +83,12 @@ public function delete(core_kernel_classes_Resource $resource, $deleteReference * @return core_kernel_classes_Class */ public function setRange(core_kernel_classes_Resource $resource, core_kernel_classes_Class $class); - + + public function setDependsOnProperty( + core_kernel_classes_Resource $resource, + core_kernel_classes_Property $property + ): void; + /** * Short description of method setMultiple * @@ -94,7 +99,7 @@ public function setRange(core_kernel_classes_Resource $resource, core_kernel_cla * @return void */ public function setMultiple(core_kernel_classes_Resource $resource, $isMultiple); - + /** * Short description of method setLgDependent * diff --git a/core/kernel/persistence/smoothsql/class.Property.php b/core/kernel/persistence/smoothsql/class.Property.php index e4b67f4e4..34f80e54c 100644 --- a/core/kernel/persistence/smoothsql/class.Property.php +++ b/core/kernel/persistence/smoothsql/class.Property.php @@ -20,10 +20,12 @@ * 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV); * 2017 (update and modification) Open Assessment Technologies SA (under the project TAO-PRODUCT); */ - + +declare(strict_types=1); + use oat\generis\model\GenerisRdf; use oat\generis\model\OntologyRdfs; - + /** * Short description of class core_kernel_persistence_smoothsql_Property * @@ -139,6 +141,18 @@ public function setRange(core_kernel_classes_Resource $resource, core_kernel_cla return $returnValue; } + public function setDependsOnProperty( + core_kernel_classes_Resource $resource, + core_kernel_classes_Property $property + ): void { + $dependsOnProperty = new core_kernel_classes_Property( + GenerisRdf::PROPERTY_DEPENDS_ON_PROPERTY, + __METHOD__ + ); + + $this->setPropertyValue($resource, $dependsOnProperty, $property->getUri()); + } + /** * Short description of method setMultiple * @@ -150,7 +164,7 @@ public function setRange(core_kernel_classes_Resource $resource, core_kernel_cla */ public function setMultiple(core_kernel_classes_Resource $resource, $isMultiple) { - + $multipleProperty = new core_kernel_classes_Property(GenerisRdf::PROPERTY_MULTIPLE); $value = ((bool)$isMultiple) ? GenerisRdf::GENERIS_TRUE : GenerisRdf::GENERIS_FALSE ; $this->removePropertyValues($resource, $multipleProperty); @@ -168,7 +182,7 @@ public function setMultiple(core_kernel_classes_Resource $resource, $isMultiple) */ public function setLgDependent(core_kernel_classes_Resource $resource, $isLgDependent) { - + $lgDependentProperty = new core_kernel_classes_Property(GenerisRdf::PROPERTY_IS_LG_DEPENDENT, __METHOD__); $value = ((bool)$isLgDependent) ? GenerisRdf::GENERIS_TRUE : GenerisRdf::GENERIS_FALSE ; $this->removePropertyValues($resource, $lgDependentProperty); diff --git a/core/ontology/generis.rdf b/core/ontology/generis.rdf index 492a6c6f3..1ef62de21 100644 --- a/core/ontology/generis.rdf +++ b/core/ontology/generis.rdf @@ -366,4 +366,11 @@ + + + + + + + diff --git a/core/resource/DependsOnPropertyCollection.php b/core/resource/DependsOnPropertyCollection.php new file mode 100644 index 000000000..66a9ca5e0 --- /dev/null +++ b/core/resource/DependsOnPropertyCollection.php @@ -0,0 +1,33 @@ +addReport(Report::createSuccess('Models were successfully synchronized')); + } + + public function down(Schema $schema): void + { + $this->throwIrreversibleMigrationException(); + } +} diff --git a/test/unit/common/oatbox/user/UserLanguageServiceTest.php b/test/unit/common/oatbox/user/UserLanguageServiceTest.php index 70446254b..3d3b1f9e1 100644 --- a/test/unit/common/oatbox/user/UserLanguageServiceTest.php +++ b/test/unit/common/oatbox/user/UserLanguageServiceTest.php @@ -22,8 +22,12 @@ namespace oat\generis\test\unit\common\oatbox\user; +use oat\generis\model\GenerisRdf; use oat\generis\test\TestCase; +use oat\oatbox\user\User; use oat\oatbox\user\UserLanguageService; +use Prophecy\Argument; +use Prophecy\Prophecy\ObjectProphecy; class UserLanguageServiceTest extends TestCase { @@ -50,4 +54,40 @@ public function testGetDefaultLanguageForAuthoringLanguage(): void $this->assertSame($this->subject->getDefaultLanguage(), $this->subject->getAuthoringLanguage()); } + + public function testGetInterfaceLanguageReturnsDefaultLanguageWhenUserDoesNotHaveItSet(): void + { + $user = $this->createUser(); + + $this->assertSame($this->subject->getDefaultLanguage(), $this->subject->getInterfaceLanguage($user)); + } + + public function testGetInterfaceLanguageReturnsLanguageFromUser(): void + { + $user = $this->createUser('en-US'); + + $this->assertSame('en-US', $this->subject->getInterfaceLanguage($user)); + } + + public function testGetInterfaceLanguageReturnsCustomInterfaceLanguage(): void + { + $this->subject->setCustomInterfaceLanguage('es-ES'); + + $user = $this->createUser(); + + $this->assertSame('es-ES', $this->subject->getInterfaceLanguage($user)); + } + + private function createUser(?string $withLanguage = null): User + { + /** @var User|ObjectProphecy $user */ + $user = $this->prophesize(User::class); + + if ($withLanguage !== null) { + $user->getPropertyValues(Argument::is(GenerisRdf::PROPERTY_USER_UILG)) + ->willReturn([$withLanguage]); + } + + return $user->reveal(); + } }