Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create new methods on resource to make ACL faster #1077

Merged
28 changes: 28 additions & 0 deletions common/oatbox/event/BulkEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?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) 2023 (original work) Open Assessment Technologies SA.
*/

declare(strict_types=1);

namespace oat\oatbox\event;

interface BulkEvent extends Event
{
public function getValues(): array;
}
52 changes: 52 additions & 0 deletions core/kernel/classes/class.Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,58 @@ public function isInstanceOf(core_kernel_classes_Class $class): bool
return (bool) $returnValue;
}

public function getParentClassesIds(): array
{
$implementation = $this->getImplementation();

if ($implementation instanceof core_kernel_persistence_smoothsql_Resource) {
return $implementation->getParentClassesIds($this->getUri());
}

return [];
}

/**
* @return array [
* '{classUri}' => [
* '{resourceUri_1}',
* '{resourceUri_N...}',
* ]
* ]
*/
public function getParentClassesResourceIds(array $classIds = null): array
{
$implementation = $this->getImplementation();

if ($implementation instanceof core_kernel_persistence_smoothsql_Resource) {
return $implementation->getClassesResourceIds($classIds ?? $this->getParentClassesIds());
}

return [];
}

/**
* Returns a list of nested resources/classes under a resource
*
* @return array [
* [
* 'id' => '{resourceId}',
* 'isClass' => true|false,
* 'level' => 1..N,
* ]
* ]
*/
public function getNestedResources(): array
{
$implementation = $this->getImplementation();

if ($implementation instanceof core_kernel_persistence_smoothsql_Resource) {
return $implementation->getNestedResources($this->getUri());
}

return [];
}

public function getServiceManager(): ServiceLocatorInterface
{
return ($this->getModel() instanceof ServiceLocatorAwareInterface)
Expand Down
138 changes: 138 additions & 0 deletions core/kernel/persistence/smoothsql/class.Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/

use oat\generis\model\OntologyRdf;
use oat\generis\model\OntologyRdfs;
use oat\oatbox\session\SessionService;
use oat\oatbox\user\UserLanguageServiceInterface;
use oat\generis\model\kernel\uri\UriProvider;
Expand Down Expand Up @@ -102,6 +103,143 @@ public function getTypes(core_kernel_classes_Resource $resource)
return (array) $returnValue;
}

public function getParentClassesIds(string $resourceUri): array
{
$query = <<<'SQL'
WITH RECURSIVE statements_tree AS (
SELECT
r.object
FROM statements r
WHERE r.subject = ?
AND r.predicate IN (?, ?)
AND r.object != ?
UNION ALL
SELECT
s.object
FROM statements s
JOIN statements_tree st
ON s.subject = st.object
AND s.predicate IN (?, ?)
AND s.object NOT IN (?, ?, ?, ?)
)
SELECT object FROM statements_tree;
SQL;

$statement = $this->getPersistence()->query(
$query,
[
$resourceUri,
OntologyRdfs::RDFS_SUBCLASSOF,
OntologyRdf::RDF_TYPE,
'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject',
OntologyRdfs::RDFS_SUBCLASSOF,
OntologyRdf::RDF_TYPE,
'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject',
'http://www.tao.lu/Ontologies/TAO.rdf#TAOObject',
'http://www.tao.lu/Ontologies/generis.rdf#generis_Ressource',
'http://www.w3.org/2000/01/rdf-schema#Resource',
]
);

return array_column($statement->fetchAll(), 'object');
}

/**
* @param array $classIds
* @return array [
* '{classUri}' => [
* '{resourceUri_1}',
* '{resourceUri_N...}',
* ]
* ]
*/
public function getClassesResourceIds(array $classIds): array
{
if (empty($classIds)) {
return [];
}

$query = sprintf(
'SELECT subject, object FROM statements WHERE predicate IN (?, ?) AND object IN (%s)',
implode(',', array_fill(0, count($classIds), '?'))
);

$statement = $this->getPersistence()->query(
$query,
[
OntologyRdfs::RDFS_SUBCLASSOF,
OntologyRdf::RDF_TYPE,
...$classIds,
]
);

$results = $statement->fetchAll();
$resourceIds = [];

// Iterate over the provided class IDs to keep the same order
foreach ($classIds as $classId) {
$resources = array_filter($results, static fn (array $result): bool => $result['object'] === $classId);
$resourceIds[$classId] = array_column($resources, 'subject');
}

return $resourceIds;
}

/**
* Returns a list of nested resources/classes under a resource
*
* @param string $classId
* @return array [
* [
* 'id' => '{resourceId}',
* 'isClass' => true|false,
* 'level' => 1..N,
* ]
* ]
*/
public function getNestedResources(string $classId): array
{
$query = <<<'SQL'
WITH RECURSIVE statements_tree AS (
SELECT
r.subject,
r.predicate,
1 as level
FROM statements r
WHERE r.subject = ?
AND r.predicate IN (?, ?)
UNION ALL
SELECT
s.subject,
s.predicate,
level + 1
FROM statements s
JOIN statements_tree st
ON s.object = st.subject
WHERE s.predicate IN (?, ?)
)
SELECT
subject as id,
CASE WHEN predicate = ? THEN 1 ELSE 0 END as isClass,
level
FROM statements_tree;
SQL;

$statement = $this->getPersistence()->query(
$query,
[
$classId,
OntologyRdfs::RDFS_SUBCLASSOF,
OntologyRdf::RDF_TYPE,
OntologyRdfs::RDFS_SUBCLASSOF,
OntologyRdf::RDF_TYPE,
OntologyRdfs::RDFS_SUBCLASSOF,
]
);

return $statement->fetchAll();
}

/**
* Short description of method getPropertyValues
*
Expand Down
Loading