@@ -356,6 +356,8 @@ class Model {
356356 private function construct_from_internal (mixed $ id = null , mixed $ parent_id = null ): void {
357357 # Do not try to load the object from internal if the skip_init flag is set
358358 if ($ this ->skip_init ) {
359+ $ this ->id = $ id ;
360+ $ this ->parent_id = $ parent_id ;
359361 return ;
360362 }
361363
@@ -1567,79 +1569,6 @@ class Model {
15671569 $ this ->apply ();
15681570 }
15691571
1570- /**
1571- * Fetches Model objects for all objects stored in the internal pfSense values. If `config_path` is set, this will
1572- * load Model objects for each object stored at the config path. If `internal_callable` is set, this will create
1573- * Model objects for each object returned by the specified callable.
1574- * @param mixed|null $parent_id Specifies the ID of the parent Model to read all objects from. This is required for
1575- * $many Models with a $parent_model_class. This value has no affect otherwise.
1576- * @param int $offset The starting point in the dataset to be used with $limit. This is only applicable to $many
1577- * enabled Models.
1578- * @param int $limit The maximum number of Model objects to retrieve. This is only applicable to $many
1579- * enabled Models.
1580- * @return ModelSet|Model Returns a ModelSet of Models if `many` is enabled or a single Model object if `many` is
1581- * not enabled.
1582- */
1583- public static function read_all (mixed $ parent_id = null , int $ limit = 0 , int $ offset = 0 ): ModelSet |Model {
1584- # Variables
1585- $ model_name = get_called_class ();
1586- $ model = new $ model_name (parent_id: $ parent_id );
1587- $ model_objects = [];
1588- $ is_parent_model_many = $ model ->is_parent_model_many ();
1589- $ requests_pagination = ($ limit or $ offset );
1590- $ offset_counter = 0 ;
1591-
1592- # Throw an error if this Model has a $many parent Model, but no parent Model ID was given
1593- if ($ is_parent_model_many and !isset ($ parent_id )) {
1594- throw new ValidationError (
1595- message: 'Field `parent_id` is required to read all. ' ,
1596- response_id: 'MODEL_PARENT_ID_REQUIRED ' ,
1597- );
1598- }
1599-
1600- # Throw an error if pagination was requested on a Model without $many enabled
1601- if (!$ model ->many and $ requests_pagination ) {
1602- throw new ValidationError (
1603- message: "Model ` $ model ->verbose_name ` does not support pagination. Please remove the `limit` and/or. " .
1604- '`offset`parameters and try again. ' ,
1605- response_id: 'MODEL_DOES_NOT_SUPPORT_PAGINATION ' ,
1606- );
1607- }
1608-
1609- # Obtain all of this Model's internally stored objects
1610- $ internal_objects = $ model ->get_internal_objects ();
1611-
1612- # For non `many` Models, wrap the internal object in an array so we can loop
1613- $ internal_objects = $ model ->many ? $ internal_objects : [$ internal_objects ];
1614-
1615- # Loop through each internal object and create a Model object for it
1616- foreach ($ internal_objects as $ internal_id => $ internal_object ) {
1617- # Do not include this object if we have not reached our offset
1618- if ($ offset_counter < $ offset ) {
1619- $ offset_counter ++;
1620- continue ;
1621- }
1622-
1623- # Create a new Model object for this internal object and assign its ID
1624- $ model_object = new $ model (id: $ internal_id , parent_id: $ parent_id );
1625-
1626- # Populate the Model object using its current internal values and add it to the array of all Model objects
1627- $ model_object ->from_internal_object ($ internal_object );
1628- $ model_objects [] = $ model_object ;
1629-
1630- # Break the loop if $limit is set, and we've met our limit of objects to obtain
1631- if ($ limit and $ limit === count ($ model_objects )) {
1632- break ;
1633- }
1634-
1635- # Increase the offset counter
1636- $ offset_counter ++;
1637- }
1638-
1639- # Unwrap the array for non `many` Models, otherwise return all objects
1640- return $ model ->many ? new ModelSet ($ model_objects ) : $ model_objects [0 ];
1641- }
1642-
16431572 /**
16441573 * Sorts `many` Model entries internally before writing the changes to config. This is useful for Model's whose
16451574 * internal objects must be written in a specific order.
@@ -1739,6 +1668,82 @@ class Model {
17391668 }
17401669 }
17411670
1671+ /**
1672+ * Fetches Model objects for all objects stored in the internal pfSense values. If `config_path` is set, this will
1673+ * load Model objects for each object stored at the config path. If `internal_callable` is set, this will create
1674+ * Model objects for each object returned by the specified callable.
1675+ * @param mixed|null $parent_id Specifies the ID of the parent Model to read all objects from. This is required for
1676+ * $many Models with a $parent_model_class. This value has no affect otherwise.
1677+ * @param int $offset The starting point in the dataset to be used with $limit. This is only applicable to $many
1678+ * enabled Models.
1679+ * @param int $limit The maximum number of Model objects to retrieve. This is only applicable to $many
1680+ * enabled Models.
1681+ * @return ModelSet|Model Returns a ModelSet of Models if `many` is enabled or a single Model object if `many` is
1682+ * not enabled.
1683+ */
1684+ public static function read_all (mixed $ parent_id = null , int $ limit = 0 , int $ offset = 0 ): ModelSet |Model {
1685+ # Variables
1686+ $ model_name = get_called_class ();
1687+ $ model = new $ model_name (parent_id: $ parent_id );
1688+ $ model_objects = [];
1689+ $ is_parent_model_many = $ model ->is_parent_model_many ();
1690+ $ requests_pagination = ($ limit or $ offset );
1691+ $ offset_counter = 0 ;
1692+
1693+ # Throw an error if this Model has a $many parent Model, but no parent Model ID was given
1694+ if ($ is_parent_model_many and !isset ($ parent_id )) {
1695+ throw new ValidationError (
1696+ message: 'Field `parent_id` is required to read all. ' ,
1697+ response_id: 'MODEL_PARENT_ID_REQUIRED ' ,
1698+ );
1699+ }
1700+
1701+ # Throw an error if pagination was requested on a Model without $many enabled
1702+ if (!$ model ->many and $ requests_pagination ) {
1703+ throw new ValidationError (
1704+ message: "Model ` $ model ->verbose_name ` does not support pagination. Please remove the `limit` and/or. " .
1705+ '`offset`parameters and try again. ' ,
1706+ response_id: 'MODEL_DOES_NOT_SUPPORT_PAGINATION ' ,
1707+ );
1708+ }
1709+
1710+ # Obtain all of this Model's internally stored objects
1711+ $ internal_objects = $ model ->get_internal_objects ();
1712+
1713+ # For non `many` Models, wrap the internal object in an array so we can loop
1714+ $ internal_objects = $ model ->many ? $ internal_objects : [$ internal_objects ];
1715+
1716+ # Loop through each internal object and create a Model object for it
1717+ foreach ($ internal_objects as $ internal_id => $ internal_object ) {
1718+ # Do not include this object if we have not reached our offset
1719+ if ($ offset_counter < $ offset ) {
1720+ $ offset_counter ++;
1721+ continue ;
1722+ }
1723+
1724+ # Create a new Model object for this internal object and assign its ID
1725+ $ model_object = new $ model (id: $ internal_id , parent_id: $ parent_id , skip_init: true );
1726+
1727+ # Obtain the parent Model object if this Model has a parent Model class assigned
1728+ $ model_object ->get_parent_model ();
1729+
1730+ # Populate the Model object using its current internal values and add it to the array of all Model objects
1731+ $ model_object ->from_internal_object ($ internal_object );
1732+ $ model_objects [] = $ model_object ;
1733+
1734+ # Break the loop if $limit is set, and we've met our limit of objects to obtain
1735+ if ($ limit and $ limit === count ($ model_objects )) {
1736+ break ;
1737+ }
1738+
1739+ # Increase the offset counter
1740+ $ offset_counter ++;
1741+ }
1742+
1743+ # Unwrap the array for non `many` Models, otherwise return all objects
1744+ return $ model ->many ? new ModelSet ($ model_objects ) : $ model_objects [0 ];
1745+ }
1746+
17421747 /**
17431748 * Performs a query on all Model objects for this Model. This is essentially a shorthand way of calling
17441749 * `query()`. This method is only applicable to `many` Models.
@@ -1766,10 +1771,43 @@ class Model {
17661771 # Merge the $query_params and any provided variable-length arguments into a single variable
17671772 $ query_params = array_merge ($ query_params , $ vl_query_params );
17681773
1769- return self ::read_all (parent_id: $ parent_id , limit: $ limit , offset: $ offset )->query (
1770- query_params: $ query_params ,
1771- excluded: $ excluded ,
1772- );
1774+ # If no query parameters were provided, just run read_all() with pagination for optimal performance
1775+ if (!$ query_params ) {
1776+ return self ::read_all (parent_id: $ parent_id , limit: $ limit , offset: $ offset );
1777+ }
1778+
1779+ # Perform the query against all Model objects for this Model first
1780+ $ modelset = self ::read_all (parent_id: $ parent_id )->query (query_params: $ query_params , excluded: $ excluded );
1781+
1782+ # Apply pagination to limit the number of objects returned if requested
1783+ $ modelset ->model_objects = self ::paginate ($ modelset ->model_objects , $ limit , $ offset );
1784+ return $ modelset ;
1785+ }
1786+
1787+ /**
1788+ * Paginates a given array but obtaining a smaller subset of the array based on the provided limit and offset values.
1789+ * @param int $limit The maximum number of items to return in the paginated array. Use 0 to impose no limit.
1790+ * @param int $offset The starting point in the array to begin the paginated array.
1791+ * @return array The paginated array containing only the subset of items that match the limit and offset values.
1792+ */
1793+ public static function paginate (array $ array , int $ limit , int $ offset ): array {
1794+ # Return the entire array if no limit or offset is set
1795+ if (!$ limit and !$ offset ) {
1796+ return $ array ;
1797+ }
1798+
1799+ # Return an empty array if the offset is greater than the array length
1800+ if ($ offset >= count ($ array )) {
1801+ return [];
1802+ }
1803+
1804+ # Return the entire array if the limit is set to 0
1805+ if (!$ limit ) {
1806+ return array_slice ($ array , $ offset );
1807+ }
1808+
1809+ # Return the subset of the array that matches the limit and offset values
1810+ return array_slice ($ array , $ offset , $ limit );
17731811 }
17741812
17751813 /**
0 commit comments