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

Adtional functions for object service #111

Merged
6 changes: 3 additions & 3 deletions lib/Db/AuditTrailMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters
/**
* Finds all audit trails for a given object
*
* @param string $idOrUuid The id or uuid of the object
* @param string $identifier The id or uuid of the object
* @return array The audit trails
*/
public function findAllUuid(string $idOrUuid, ?int $limit = null, ?int $offset = null, ?array $filters = [], ?array $searchConditions = [], ?array $searchParams = []): array
public function findAllUuid(string $identifier, ?int $limit = null, ?int $offset = null, ?array $filters = [], ?array $searchConditions = [], ?array $searchParams = []): array
{
try {
$object = $this->objectEntityMapper->find(idOrUuid: $idOrUuid);
$object = $this->objectEntityMapper->find(identifier: $identifier);
$objectId = $object->getId();
$filters['object'] = $objectId;
return $this->findAll($limit, $offset, $filters, $searchConditions, $searchParams);
Expand Down
7 changes: 4 additions & 3 deletions lib/Db/ObjectEntityMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@ public function __construct(IDBConnection $db, MySQLJsonService $mySQLJsonServic
* @param int|string $idOrUuid The ID or UUID of the object to find
* @return ObjectEntity The ObjectEntity
*/
public function find($idOrUuid): ObjectEntity
public function find($identifier): ObjectEntity
{
$qb = $this->db->getQueryBuilder();

$qb->select('*')
->from('openregister_objects')
->where(
$qb->expr()->orX(
$qb->expr()->eq('id', $qb->createNamedParameter($idOrUuid, IQueryBuilder::PARAM_INT)),
$qb->expr()->eq('uuid', $qb->createNamedParameter($idOrUuid, IQueryBuilder::PARAM_STR))
$qb->expr()->eq('id', $qb->createNamedParameter($identifier, IQueryBuilder::PARAM_INT)),
$qb->expr()->eq('uuid', $qb->createNamedParameter($identifier, IQueryBuilder::PARAM_STR)),
$qb->expr()->eq('uri', $qb->createNamedParameter($identifier, IQueryBuilder::PARAM_STR))
)
);

Expand Down
203 changes: 157 additions & 46 deletions lib/Service/ObjectService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use OCA\OpenRegister\Db\ObjectEntityMapper;
use OCA\OpenRegister\Db\AuditTrail;
use OCA\OpenRegister\Db\AuditTrailMapper;
use OCA\OpenRegister\Db\ObjectAuditLogMapper;
use OCA\OpenRegister\Exception\ValidationException;
use OCA\OpenRegister\Formats\BsnFormat;
use OCP\App\IAppManager;
Expand Down Expand Up @@ -67,6 +68,7 @@ public function __construct(
RegisterMapper $registerMapper,
SchemaMapper $schemaMapper,
AuditTrailMapper $auditTrailMapper,
ObjectAuditLogMapper $objectAuditLogMapper,
private ContainerInterface $container,
private readonly IURLGenerator $urlGenerator,
private readonly FileService $fileService,
Expand All @@ -77,6 +79,7 @@ public function __construct(
$this->registerMapper = $registerMapper;
$this->schemaMapper = $schemaMapper;
$this->auditTrailMapper = $auditTrailMapper;
$this->objectAuditLogMapper = $objectAuditLogMapper;
}

/**
Expand Down Expand Up @@ -130,10 +133,10 @@ public function validateObject(array $object, ?int $schemaId = null, object $sch
* @param int|string $id The ID or UUID to search for
* @param array|null $extend Properties to extend with related data
*
* @return ObjectEntity The found object
* @return ObjectEntity|null The found object or null if not found
* @throws Exception
*/
public function find(int|string $id, ?array $extend = []): ObjectEntity
public function find(int|string $id, ?array $extend = []): ?ObjectEntity
{
return $this->getObject(
register: $this->registerMapper->find($this->getRegister()),
Expand Down Expand Up @@ -223,7 +226,14 @@ public function delete(array|\JsonSerializable $object): bool
*
* @return array List of matching objects
*/
public function findAll(?int $limit = null, ?int $offset = null, array $filters = [], array $sort = [], ?string $search = null, ?array $extend = []): array
public function findAll(
?int $limit = null,
?int $offset = null,
array $filters = [],
array $sort = [],
?string $search = null,
?array $extend = []
): array
{
$objects = $this->getObjects(
register: $this->getRegister(),
Expand All @@ -235,6 +245,15 @@ public function findAll(?int $limit = null, ?int $offset = null, array $filters
search: $search
);

// If extend is provided, extend each object
if (!empty($extend)) {
$objects = array_map(function($object) use ($extend) {
// Convert object to array if needed
$objectArray = is_array($object) ? $object : $object->jsonSerialize();
return $this->extendEntity(entity: $objectArray, extend: $extend);
}, $objects);
}

return $objects;
}

Expand Down Expand Up @@ -406,7 +425,16 @@ public function findAllPaginated(array $requestParams): array
*
* @return array The retrieved objects.
*/
public function getObjects(?string $objectType = null, ?int $register = null, ?int $schema = null, ?int $limit = null, ?int $offset = null, array $filters = [], array $sort = [], ?string $search = null, ?array $extend = []): array
public function getObjects(
?string $objectType = null,
?int $register = null,
?int $schema = null,
?int $limit = null,
?int $offset = null,
array $filters = [],
array $sort = [],
?string $search = null
)
{
// Set object type and filters if register and schema are provided
if ($objectType === null && $register !== null && $schema !== null) {
Expand All @@ -419,7 +447,13 @@ public function getObjects(?string $objectType = null, ?int $register = null, ?i
$mapper = $this->getMapper($objectType);

// Use the mapper to find and return all objects of the specified type
return $mapper->findAll(limit: $limit, offset: $offset, filters: $filters, sort: $sort, search: $search);
return $mapper->findAll(
limit: $limit,
offset: $offset,
filters: $filters,
sort: $sort,
search: $search
);
}

/**
Expand All @@ -435,6 +469,11 @@ public function getObjects(?string $objectType = null, ?int $register = null, ?i
*/
public function saveObject(int $register, int $schema, array $object): ObjectEntity
{
// Remove system properties (starting with _)
$object = array_filter($object, function($key) {
return !str_starts_with($key, '_');
}, ARRAY_FILTER_USE_KEY);

// Convert register and schema to their respective objects if they are strings // @todo ???
if (is_string($register)) {
$register = $this->registerMapper->find($register);
Expand All @@ -453,8 +492,6 @@ public function saveObject(int $register, int $schema, array $object): ObjectEnt
);
}

// $validationResult = $this->validateObject(object: $object, schemaId: $schema);

// Create new entity if none exists
if (isset($object['id']) === false || $objectEntity === null) {
$objectEntity = new ObjectEntity();
Expand Down Expand Up @@ -482,26 +519,22 @@ public function saveObject(int $register, int $schema, array $object): ObjectEnt
// Let grap any links that we can
$objectEntity = $this->handleLinkRelations($objectEntity, $object);

$schemaObject = $this->schemaMapper->find($schema);
$schemaObject = $this->schemaMapper->find($schema);

// Handle object properties that are either nested objects or files
if ($schemaObject->getProperties() !== null && is_array($schemaObject->getProperties()) === true) {
$objectEntity = $this->handleObjectRelations($objectEntity, $object, $schemaObject->getProperties(), $register, $schema);
}

$objectEntity->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openregister.Objects.show', ['id' => $objectEntity->getUuid()])));
$objectEntity->setUri($this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('openregister.Objects.show', ['id' => $objectEntity->getUuid()])));

if ($objectEntity->getId()) {// && ($schemaObject->getHardValidation() === false || $validationResult->isValid() === true)){
$objectEntity = $this->objectEntityMapper->update($objectEntity);
$this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject);
} else {//if ($schemaObject->getHardValidation() === false || $validationResult->isValid() === true) {
$objectEntity = $this->objectEntityMapper->insert($objectEntity);
$this->auditTrailMapper->createAuditTrail(new: $objectEntity);
}

// if ($validationResult->isValid() === false) {
// throw new ValidationException(message: 'The object could not be validated', errors: $validationResult->error());
// }
if ($objectEntity->getId()) {
$objectEntity = $this->objectEntityMapper->update($objectEntity);
$this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject);
} else {
$objectEntity = $this->objectEntityMapper->insert($objectEntity);
$this->auditTrailMapper->createAuditTrail(new: $objectEntity);
}

return $objectEntity;
}
Expand Down Expand Up @@ -824,12 +857,11 @@ private function handleFileProperty(ObjectEntity $objectEntity, array $object, s
* @param string $uuid The UUID of the object to get
* @param array $extend Properties to extend with related data
*
* @return ObjectEntity The resulting object
* @return ObjectEntity|null The resulting object or null if not found
* @throws Exception If source type is unsupported
*/
public function getObject(Register $register, Schema $schema, string $uuid, ?array $extend = []): ObjectEntity
public function getObject(Register $register, Schema $schema, string $uuid, ?array $extend = []): ?ObjectEntity
{

// Handle internal source
if ($register->getSource() === 'internal' || $register->getSource() === '') {
return $this->objectEntityMapper->findByUuid($register, $schema, $uuid);
Expand Down Expand Up @@ -981,7 +1013,7 @@ public function renderEntity(array $entity, ?array $extend = []): array
* @param mixed $entity The entity to extend
* @param array $extend Properties to extend with related data
* @return array The extended entity as an array
* @throws Exception If property not found or no mapper available
* @throws Exception If property not found
*/
public function extendEntity(array $entity, array $extend): array
{
Expand Down Expand Up @@ -1009,26 +1041,48 @@ public function extendEntity(array $entity, array $extend): array
}

// Try to get mapper for property
$propertyObject = $property;
try {
$mapper = $this->getMapper(objectType: $property);
$propertyObject = $singularProperty;

// Extend with related objects using specific mapper
if (is_array($value) === true) {
$result[$property] = $this->getMultipleObjects(objectType: $propertyObject, ids: $value);
} else {
$objectId = is_object(value: $value) ? $value->getId() : $value;
$result[$property] = $mapper->find($objectId);
}
} catch (Exception $e) {
// If no specific mapper found, try to look up values in default database
try {
$mapper = $this->getMapper(objectType: $singularProperty);
$propertyObject = $singularProperty;
} catch (Exception $e) {
throw new Exception("No mapper available for property '$property'.");
if (is_array($value)) {
// Handle array of values
$extendedValues = [];
foreach ($value as $val) {
try {
$found = $this->objectEntityMapper->find($val);
if ($found) {
$extendedValues[] = $found;
}
} catch (Exception $e) {
continue;
}
}
if (!empty($extendedValues)) {
$result[$property] = $extendedValues;
}
} else {
// Handle single value
$found = $this->objectEntityMapper->find($value);
if ($found) {
$result[$property] = $found;
}
}
} catch (Exception $e2) {
// If lookup fails, keep original value
continue;
}
}

// Extend with related objects
if (is_array($value) === true) {
$result[$property] = $this->getMultipleObjects(objectType: $propertyObject, ids: $value);
} else {
$objectId = is_object(value: $value) ? $value->getId() : $value;
$result[$property] = $mapper->find($objectId);
}
}

return $result;
Expand Down Expand Up @@ -1104,19 +1158,76 @@ public function setSchema(int $schema): void
/**
* Get the audit trail for a specific object
*
* @todo: register and schema parameters are not needed anymore
*
* @param int $register The register ID
* @param int $schema The schema ID
* @param string $id The object ID
* @param int|null $register Optional register ID to override current register
* @param int|null $schema Optional schema ID to override current schema
* @return array The audit trail entries
*/
public function getAuditTrail(int $register, int $schema, string $id): array
public function getAuditTrail(string $id, ?int $register = null, ?int $schema = null): array
{
// Get the object to get its URI and UUID
$object = $this->find($id);

// @todo this is not working, it fails to find the logs
$auditTrails = $this->auditTrailMapper->findAll(filters: ['object' => $object->getId()]);

return $auditTrails;
}

/**
* Get all relations for a specific object
* Returns objects that link to this object (incoming references)
*
* @param string $id The object ID
* @param int|null $register Optional register ID to override current register
* @param int|null $schema Optional schema ID to override current schema
* @return array The objects that reference this object
*/
public function getRelations(string $id, ?int $register = null, ?int $schema = null): array
{
$register = $register ?? $this->getRegister();
$schema = $schema ?? $this->getSchema();

// Get the object to get its URI and UUID
$object = $this->find($id);

// Find objects that reference this object's URI or UUID
$referencingObjects = $this->objectEntityMapper->findByRelationUri(
search: $object->getUuid(),
partialMatch: true
);

// Filter out self-references if any
return array_filter($referencingObjects, function($referencingObject) use ($id) {
return $referencingObject->getUuid() !== $id;
});
}

/**
* Get all uses of a specific object
* Returns objects that this object links to (outgoing references)
*
* @param string $id The object ID
* @param int|null $register Optional register ID to override current register
* @param int|null $schema Optional schema ID to override current schema
* @return array The objects this object references
*/
public function getUses(string $id, ?int $register = null, ?int $schema = null): array
{
$filters = [
'object' => $id
];
// First get the object to access its relations
$object = $this->find($id);
$relations = $object->getRelations() ?? [];

// Get all referenced objects
$referencedObjects = [];
foreach ($relations as $path => $relationId) {
$referencedObjects[$path] = $this->objectEntityMapper->find($relationId);

if($referencedObjects[$path] === null){
$referencedObjects[$path] = $relationId;
}
}

return $this->auditTrailMapper->findAllUuid(idOrUuid: $id);
return $referencedObjects;
}
}
Loading