diff --git a/functions.php b/functions.php index 21b8b83..1c36911 100644 --- a/functions.php +++ b/functions.php @@ -252,4 +252,54 @@ function send_email(string $subject, string $body, string $altBody, string $to_a $mail->send(); } -?> \ No newline at end of file + +/** + * Collects related objects for each origin object based on a given foreign key. + * + * Returns an array in the following format: + * [ + * [ + * 'origin' => $object, // the origin object + * 'relations' => $objects // related objects from the target model + * ], + * ... + * ] + * + * @param array $objects Array of origin objects (their IDs will be used for matching) + * @param string $model_name_format Target model name in "app:model" format to fetch related objects from + * @param string $field_key Foreign key in the related model that refers to the origin object ID + * @return array An array of relation mappings between origin and related objects + */ +function prefetch_related(array $objects, string $model_name_format, string $field_key) +{ + [$app, $model] = explode(':', $model_name_format); + $model_name = "Lycoreco\Apps\\" . $app . "\Models\\" . $model; + + if (!class_exists($model_name)) { + throw new InvalidArgumentException("Model class $model_name does not exist."); + } + + $keys = $keys = array_map(fn($obj) => $obj->get_id(), $objects); + + if (empty($keys)) + return []; + + $related_objects = $model_name::filter(array( + [ + 'name' => 'obj.' . $field_key, + 'type' => 'IN', + 'value' => $keys + ] + )); + + return array_map(function ($object) use ($related_objects, $field_key) { + $rels = array_filter($related_objects, function ($rel) use ($object, $field_key) { + return $rel->{'field_' . $field_key} == $object->get_id(); + }); + + return [ + 'origin' => $object, + 'relations' => array_values($rels) + ]; + }, $objects); +}