Update 2024-09-05 01:21:23

This commit is contained in:
Robot 2024-09-05 01:21:47 +02:00
parent b894dfc8af
commit 92c4b2881e
Signed by untrusted user: Robot
GPG Key ID: 14DECD44E7E1BB95
13 changed files with 264 additions and 64 deletions

View File

@ -15,6 +15,7 @@ class UsersSubform << (F,LightGreen) >> #RoyalBlue {
# Items $items # Items $items
# string $table # string $table
# array $user # array $user
# array $activeUsers
+ __construct(Items $items, ?string $table = null) + __construct(Items $items, ?string $table = null)
+ table(string $table) : self + table(string $table) : self
+ get(string $linkValue, string $linkKey, ...) : ?array + get(string $linkValue, string $linkKey, ...) : ?array
@ -26,8 +27,9 @@ class UsersSubform << (F,LightGreen) >> #RoyalBlue {
- getUserDetails(array $item) : void - getUserDetails(array $item) : void
- converter(array $items, array $keySet, ...) : array - converter(array $items, array $keySet, ...) : array
- process(mixed $items, string $indexKey, ...) : array - process(mixed $items, string $indexKey, ...) : array
- setUserDetails(array $item) : int - getActiveUsers(string $linkKey, string $linkValue) : array
- loadUser(array $item) : ?User - setUserDetails(array $item, array $activeUsers) : int
- loadUser(array $item, array $activeUsers) : ?User
- extractUserDetails(array $item, ?User $user) : array - extractUserDetails(array $item, ?User $user) : array
- assignUserGroups($details, ?User $user, ...) : void - assignUserGroups($details, ?User $user, ...) : void
- saveUserDetails(array $details, int $userId) : int - saveUserDetails(array $details, int $userId) : int
@ -139,7 +141,14 @@ note right of UsersSubform::process
string $linkValue string $linkValue
end note end note
note left of UsersSubform::setUserDetails note left of UsersSubform::getActiveUsers
Get current active Users Linked to this entity
since: 5.0.2
return: array
end note
note right of UsersSubform::setUserDetails
Handles setting user details and saving them. Handles setting user details and saving them.
This function retrieves the user by ID, sets the user details, This function retrieves the user by ID, sets the user details,
and adds appropriate user groups before saving the user. and adds appropriate user groups before saving the user.
@ -148,21 +157,21 @@ and adds appropriate user groups before saving the user.
return: int return: int
end note end note
note right of UsersSubform::loadUser note left of UsersSubform::loadUser
Load the user based on the user ID from the item array. Load the user based on the user ID from the item array.
since: 5.0.2 since: 5.0.2
return: ?User return: ?User
end note end note
note left of UsersSubform::extractUserDetails note right of UsersSubform::extractUserDetails
Extract user details from the item array and prepare them for saving. Extract user details from the item array and prepare them for saving.
since: 5.0.2 since: 5.0.2
return: array return: array
end note end note
note right of UsersSubform::assignUserGroups note left of UsersSubform::assignUserGroups
Assigns user groups based on existing groups and entity type. Assigns user groups based on existing groups and entity type.
since: 5.0.2 since: 5.0.2
@ -174,7 +183,7 @@ note right of UsersSubform::assignUserGroups
array $item array $item
end note end note
note left of UsersSubform::saveUserDetails note right of UsersSubform::saveUserDetails
Save the user details using UserHelper and handle exceptions. Save the user details using UserHelper and handle exceptions.
since: 5.0.2 since: 5.0.2

View File

@ -61,6 +61,14 @@ final class UsersSubform implements GuidInterface, SubformInterface
*/ */
protected array $user; protected array $user;
/**
* The active users
*
* @var array
* @since 5.0.2
*/
protected array $activeUsers = [];
/** /**
* Constructor. * Constructor.
* *
@ -336,7 +344,7 @@ final class UsersSubform implements GuidInterface, SubformInterface
private function process($items, string $indexKey, string $linkKey, string $linkValue): array private function process($items, string $indexKey, string $linkKey, string $linkValue): array
{ {
$items = is_array($items) ? $items : []; $items = is_array($items) ? $items : [];
foreach ($items as &$item) foreach ($items as $n => &$item)
{ {
$value = $item[$indexKey] ?? ''; $value = $item[$indexKey] ?? '';
switch ($indexKey) { switch ($indexKey) {
@ -357,29 +365,69 @@ final class UsersSubform implements GuidInterface, SubformInterface
// No action for other keys if empty // No action for other keys if empty
break; break;
} }
// set LINK // set LINK
$item[$linkKey] = $linkValue; $item[$linkKey] = $linkValue;
// create/update user // create/update user
$item['user_id'] = $this->setUserDetails($item); $item['user_id'] = $this->setUserDetails(
$item,
$this->getActiveUsers(
$linkKey,
$linkValue
)
);
// remove empty row (means no user linked)
if ($item['user_id'] == 0)
{
unset($items[$n]);
}
} }
return array_values($items); return array_values($items);
} }
/**
* Get current active Users Linked to this entity
*
* @param string $linkKey The link key on which the items where linked in the child table.
* @param string $linkValue The value of the link key in child table.
*
* @return array The IDs of all active users.
* @since 5.0.2
*/
private function getActiveUsers(string $linkKey, string $linkValue): array
{
if (isset($this->activeUsers[$linkKey . $linkValue]))
{
return $this->activeUsers[$linkKey . $linkValue];
}
if (($users = $this->items->table($this->getTable())->values([$linkValue], $linkKey, 'user_id')) !== null)
{
$this->activeUsers[$linkKey . $linkValue] = $users;
return $users;
}
return [];
}
/** /**
* Handles setting user details and saving them. * Handles setting user details and saving them.
* *
* This function retrieves the user by ID, sets the user details, * This function retrieves the user by ID, sets the user details,
* and adds appropriate user groups before saving the user. * and adds appropriate user groups before saving the user.
* *
* @param array $item The user details passed by reference. * @param array $item The user details passed by reference.
* @param array $activeUsers The current active user linked to this entity.
* *
* @return int The ID of the saved user, or 0 on failure. * @return int The ID of the saved user, or 0 on failure.
* @since 5.0.2 * @since 5.0.2
*/ */
private function setUserDetails(array &$item): int private function setUserDetails(array &$item, array $activeUsers): int
{ {
$user = $this->loadUser($item); $user = $this->loadUser($item, $activeUsers);
$details = $this->extractUserDetails($item, $user); $details = $this->extractUserDetails($item, $user);
$this->assignUserGroups($details, $user, $item); $this->assignUserGroups($details, $user, $item);
@ -389,18 +437,25 @@ final class UsersSubform implements GuidInterface, SubformInterface
/** /**
* Load the user based on the user ID from the item array. * Load the user based on the user ID from the item array.
* *
* @param array $item The array containing user details. * @param array $item The array containing user details.
* @param array $activeUsers The current active user linked to this entity.
* *
* @return User|null The user object if found, null otherwise. * @return User|null The user object if found, null otherwise.
* @since 5.0.2 * @since 5.0.2
*/ */
private function loadUser(array $item): ?User private function loadUser(array $item, array $activeUsers): ?User
{ {
if (!isset($item['user_id']) || !is_numeric($item['user_id']) || $item['user_id'] <= 0) if (!isset($item['user_id']) || !is_numeric($item['user_id']) || $item['user_id'] <= 0)
{ {
return null; return null;
} }
// only allow update to linked users
if (!in_array($item['user_id'], $activeUsers))
{
return null;
}
$user = UserHelper::getUserById((int) $item['user_id']); $user = UserHelper::getUserById((int) $item['user_id']);
if ($user && $user->id == $item['user_id']) if ($user && $user->id == $item['user_id'])

View File

@ -29,6 +29,14 @@
*/ */
protected array $user; protected array $user;
/**
* The active users
*
* @var array
* @since 5.0.2
*/
protected array $activeUsers = [];
/** /**
* Constructor. * Constructor.
* *
@ -304,7 +312,7 @@
private function process($items, string $indexKey, string $linkKey, string $linkValue): array private function process($items, string $indexKey, string $linkKey, string $linkValue): array
{ {
$items = is_array($items) ? $items : []; $items = is_array($items) ? $items : [];
foreach ($items as &$item) foreach ($items as $n => &$item)
{ {
$value = $item[$indexKey] ?? ''; $value = $item[$indexKey] ?? '';
switch ($indexKey) { switch ($indexKey) {
@ -325,29 +333,69 @@
// No action for other keys if empty // No action for other keys if empty
break; break;
} }
// set LINK // set LINK
$item[$linkKey] = $linkValue; $item[$linkKey] = $linkValue;
// create/update user // create/update user
$item['user_id'] = $this->setUserDetails($item); $item['user_id'] = $this->setUserDetails(
$item,
$this->getActiveUsers(
$linkKey,
$linkValue
)
);
// remove empty row (means no user linked)
if ($item['user_id'] == 0)
{
unset($items[$n]);
}
} }
return array_values($items); return array_values($items);
} }
/**
* Get current active Users Linked to this entity
*
* @param string $linkKey The link key on which the items where linked in the child table.
* @param string $linkValue The value of the link key in child table.
*
* @return array The IDs of all active users.
* @since 5.0.2
*/
private function getActiveUsers(string $linkKey, string $linkValue): array
{
if (isset($this->activeUsers[$linkKey . $linkValue]))
{
return $this->activeUsers[$linkKey . $linkValue];
}
if (($users = $this->items->table($this->getTable())->values([$linkValue], $linkKey, 'user_id')) !== null)
{
$this->activeUsers[$linkKey . $linkValue] = $users;
return $users;
}
return [];
}
/** /**
* Handles setting user details and saving them. * Handles setting user details and saving them.
* *
* This function retrieves the user by ID, sets the user details, * This function retrieves the user by ID, sets the user details,
* and adds appropriate user groups before saving the user. * and adds appropriate user groups before saving the user.
* *
* @param array $item The user details passed by reference. * @param array $item The user details passed by reference.
* @param array $activeUsers The current active user linked to this entity.
* *
* @return int The ID of the saved user, or 0 on failure. * @return int The ID of the saved user, or 0 on failure.
* @since 5.0.2 * @since 5.0.2
*/ */
private function setUserDetails(array &$item): int private function setUserDetails(array &$item, array $activeUsers): int
{ {
$user = $this->loadUser($item); $user = $this->loadUser($item, $activeUsers);
$details = $this->extractUserDetails($item, $user); $details = $this->extractUserDetails($item, $user);
$this->assignUserGroups($details, $user, $item); $this->assignUserGroups($details, $user, $item);
@ -357,18 +405,25 @@
/** /**
* Load the user based on the user ID from the item array. * Load the user based on the user ID from the item array.
* *
* @param array $item The array containing user details. * @param array $item The array containing user details.
* @param array $activeUsers The current active user linked to this entity.
* *
* @return User|null The user object if found, null otherwise. * @return User|null The user object if found, null otherwise.
* @since 5.0.2 * @since 5.0.2
*/ */
private function loadUser(array $item): ?User private function loadUser(array $item, array $activeUsers): ?User
{ {
if (!isset($item['user_id']) || !is_numeric($item['user_id']) || $item['user_id'] <= 0) if (!isset($item['user_id']) || !is_numeric($item['user_id']) || $item['user_id'] <= 0)
{ {
return null; return null;
} }
// only allow update to linked users
if (!in_array($item['user_id'], $activeUsers))
{
return null;
}
$user = UserHelper::getUserById((int) $item['user_id']); $user = UserHelper::getUserById((int) $item['user_id']);
if ($user && $user->id == $item['user_id']) if ($user && $user->id == $item['user_id'])

View File

@ -19,7 +19,7 @@ abstract Model #Orange {
+ __construct(Table $table, ?string $tableName = null, ...) + __construct(Table $table, ?string $tableName = null, ...)
+ table(string $table) : self + table(string $table) : self
+ {abstract} value(mixed $value, string $field, ...) : mixed + {abstract} value(mixed $value, string $field, ...) : mixed
+ values(?array $items = null, string $field, ...) : ?array + values(?array $items, string $field, ...) : ?array
+ item(?object $item, ?string $table = null) : ?object + item(?object $item, ?string $table = null) : ?object
+ items(?array $items = null, ?string $table = null) : ?array + items(?array $items = null, ?string $table = null) : ?array
+ row(?array $item, ?string $table = null) : ?array + row(?array $item, ?string $table = null) : ?array
@ -73,7 +73,7 @@ Example: $this->items(Array, 'value_key', 'table_name');
return: ?array return: ?array
arguments: arguments:
?array $items = null ?array $items
string $field string $field
?string $table = null ?string $table = null
end note end note

View File

@ -118,7 +118,7 @@ abstract class Model implements ModelInterface
* @return array|null * @return array|null
* @since 3.2.2 * @since 3.2.2
*/ */
public function values(?array $items = null, string $field, ?string $table = null): ?array public function values(?array $items, string $field, ?string $table = null): ?array
{ {
// check if this is a valid table // check if this is a valid table
if (ArrayHelper::check($items)) if (ArrayHelper::check($items))

View File

@ -91,7 +91,7 @@
* @return array|null * @return array|null
* @since 3.2.2 * @since 3.2.2
*/ */
public function values(?array $items = null, string $field, ?string $table = null): ?array public function values(?array $items, string $field, ?string $table = null): ?array
{ {
// check if this is a valid table // check if this is a valid table
if (ArrayHelper::check($items)) if (ArrayHelper::check($items))

View File

@ -22,6 +22,7 @@ abstract UserHelper #Orange {
# {static} prepareUserData(array $credentials, int $mode) : array # {static} prepareUserData(array $credentials, int $mode) : array
- {static} adminRegister(BaseDatabaseModel $model, array $data) : int - {static} adminRegister(BaseDatabaseModel $model, array $data) : int
- {static} handlePostRegistration(int $userId, int $autologin, ...) : int - {static} handlePostRegistration(int $userId, int $autologin, ...) : int
- {static} setFormPathForUserClass(int $mode) : void
} }
note right of UserHelper::save note right of UserHelper::save
@ -110,6 +111,15 @@ note left of UserHelper::handlePostRegistration
int $autologin int $autologin
array $credentials array $credentials
end note end note
note right of UserHelper::setFormPathForUserClass
Address bug on \Joomla\CMS\MVC\Model\FormBehaviorTrait Line 76
The use of JPATH_COMPONENT cause it to load the
active component forms and fields, which breaks the registration model.
since: 5.0.3
return: void
end note
@enduml @enduml
``` ```

View File

@ -13,6 +13,7 @@ namespace VDM\Joomla\Componentbuilder\Utilities;
use Joomla\CMS\Factory; use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text; use Joomla\CMS\Language\Text;
use Joomla\CMS\User\User; use Joomla\CMS\User\User;
use Joomla\CMS\User\UserHelper as JoomlaUserHelper; use Joomla\CMS\User\UserHelper as JoomlaUserHelper;
@ -59,29 +60,32 @@ abstract class UserHelper
// Ensure the 'username' key exists in the credentials array, set to an empty string if not provided. // Ensure the 'username' key exists in the credentials array, set to an empty string if not provided.
$username = $credentials['username'] ?? $credentials['email']; $username = $credentials['username'] ?? $credentials['email'];
// Check for an existing user by email or username. // If the user's ID is set and valid, handle the update logic.
$existingEmailUserId = static::getUserIdByEmail($credentials['email']); if (!empty($credentials['id']) && $credentials['id'] > 0)
$existingUserId = static::getUserIdByUsername($username);
// If either the email or username already exists, handle the update logic.
if ($existingEmailUserId !== null || $existingUserId !== null || (isset($credentials['id']) && $credentials['id'] > 0))
{ {
// Prevent updating other users or reusing an email by different users. $userId = $credentials['id'];
$email = $credentials['email'];
// Fetch existing user by email and username.
$existingEmailUserId = static::getUserIdByEmail($email);
$existingUsernameId = static::getUserIdByUsername($username);
// Validate that we aren't attempting to update other users or reuse another user's email/username.
if ( if (
( ($existingEmailUserId && $existingEmailUserId != $userId) ||
isset($credentials['id']) && ($existingUsernameId && $existingUsernameId != $userId) ||
( ($existingEmailUserId && $existingUsernameId && $existingEmailUserId != $existingUsernameId)
($existingEmailUserId !== null && $existingEmailUserId != $credentials['id']) || ) {
($existingUserId !== null && $existingUserId != $credentials['id']) throw new NoUserIdFoundException(
Text::sprintf(
'User ID mismatch detected when trying to save %s (%s) credentials.',
$username,
$email
) )
) || ($existingUserId !== null && $existingEmailUserId !== null && $existingEmailUserId != $existingUserId) );
)
{
throw new NoUserIdFoundException(Text::sprintf('COM_COMPONENTBUILDER_USER_ID_MISMATCH_DETECTED_WHEN_TRYING_TO_SAVE_S_S_CREDENTIALS', $username, $credentials['email']));
} }
// Update the existing user. // Update the existing user.
$credentials['id'] = $credentials['id'] ?? $existingEmailUserId ?? $existingUserId;
return static::update($credentials); return static::update($credentials);
} }
@ -147,6 +151,9 @@ abstract class UserHelper
// Prepare user data // Prepare user data
$data = static::prepareUserData($credentials, $mode); $data = static::prepareUserData($credentials, $mode);
// Set form path (bug fix for Joomla)
static::setFormPathForUserClass($mode);
// Handle user creation // Handle user creation
$userId = $mode === 1 ? $model->register($data) : static::adminRegister($model, $data); $userId = $mode === 1 ? $model->register($data) : static::adminRegister($model, $data);
@ -161,6 +168,17 @@ abstract class UserHelper
} }
} }
if (!$userId)
{
$current_user = Factory::getApplication()->getIdentity();
// only allow those with access to Users to ignore errors
if ($current_user->authorise('core.manage', 'com_users'))
{
$userId = static::getUserIdByUsername($credentials['username']);
}
}
if (is_numeric($userId) && $userId > 0) if (is_numeric($userId) && $userId > 0)
{ {
// Handle post-registration processes // Handle post-registration processes
@ -427,6 +445,24 @@ abstract class UserHelper
} }
return $userId; return $userId;
}
/**
* Address bug on \Joomla\CMS\MVC\Model\FormBehaviorTrait Line 76
* The use of JPATH_COMPONENT cause it to load the
* active component forms and fields, which breaks the registration model.
*
* @param int $mode
*
* @since 5.0.3
*/
private static function setFormPathForUserClass(int $mode): void
{
if ($mode == 1) // 1 = use of the Registration Model
{
// Get the form.
Form::addFormPath(JPATH_ROOT . '/components/com_users/forms');
}
} }
} }

View File

@ -26,29 +26,32 @@
// Ensure the 'username' key exists in the credentials array, set to an empty string if not provided. // Ensure the 'username' key exists in the credentials array, set to an empty string if not provided.
$username = $credentials['username'] ?? $credentials['email']; $username = $credentials['username'] ?? $credentials['email'];
// Check for an existing user by email or username. // If the user's ID is set and valid, handle the update logic.
$existingEmailUserId = static::getUserIdByEmail($credentials['email']); if (!empty($credentials['id']) && $credentials['id'] > 0)
$existingUserId = static::getUserIdByUsername($username);
// If either the email or username already exists, handle the update logic.
if ($existingEmailUserId !== null || $existingUserId !== null || (isset($credentials['id']) && $credentials['id'] > 0))
{ {
// Prevent updating other users or reusing an email by different users. $userId = $credentials['id'];
$email = $credentials['email'];
// Fetch existing user by email and username.
$existingEmailUserId = static::getUserIdByEmail($email);
$existingUsernameId = static::getUserIdByUsername($username);
// Validate that we aren't attempting to update other users or reuse another user's email/username.
if ( if (
( ($existingEmailUserId && $existingEmailUserId != $userId) ||
isset($credentials['id']) && ($existingUsernameId && $existingUsernameId != $userId) ||
( ($existingEmailUserId && $existingUsernameId && $existingEmailUserId != $existingUsernameId)
($existingEmailUserId !== null && $existingEmailUserId != $credentials['id']) || ) {
($existingUserId !== null && $existingUserId != $credentials['id']) throw new NoUserIdFoundException(
Text::sprintf(
'User ID mismatch detected when trying to save %s (%s) credentials.',
$username,
$email
) )
) || ($existingUserId !== null && $existingEmailUserId !== null && $existingEmailUserId != $existingUserId) );
)
{
throw new NoUserIdFoundException(Text::sprintf('User ID mismatch detected when trying to save %s (%s) credentials.', $username, $credentials['email']));
} }
// Update the existing user. // Update the existing user.
$credentials['id'] = $credentials['id'] ?? $existingEmailUserId ?? $existingUserId;
return static::update($credentials); return static::update($credentials);
} }
@ -114,6 +117,9 @@
// Prepare user data // Prepare user data
$data = static::prepareUserData($credentials, $mode); $data = static::prepareUserData($credentials, $mode);
// Set form path (bug fix for Joomla)
static::setFormPathForUserClass($mode);
// Handle user creation // Handle user creation
$userId = $mode === 1 ? $model->register($data) : static::adminRegister($model, $data); $userId = $mode === 1 ? $model->register($data) : static::adminRegister($model, $data);
@ -128,6 +134,17 @@
} }
} }
if (!$userId)
{
$current_user = Factory::getApplication()->getIdentity();
// only allow those with access to Users to ignore errors
if ($current_user->authorise('core.manage', 'com_users'))
{
$userId = static::getUserIdByUsername($credentials['username']);
}
}
if (is_numeric($userId) && $userId > 0) if (is_numeric($userId) && $userId > 0)
{ {
// Handle post-registration processes // Handle post-registration processes
@ -394,4 +411,22 @@
} }
return $userId; return $userId;
}
/**
* Address bug on \Joomla\CMS\MVC\Model\FormBehaviorTrait Line 76
* The use of JPATH_COMPONENT cause it to load the
* active component forms and fields, which breaks the registration model.
*
* @param int $mode
*
* @since 5.0.3
*/
private static function setFormPathForUserClass(int $mode): void
{
if ($mode == 1) // 1 = use of the Registration Model
{
// Get the form.
Form::addFormPath(JPATH_ROOT . '/components/com_users/forms');
}
} }

View File

@ -31,6 +31,6 @@
"namespace": "[[[NamespacePrefix]]]\\Joomla\\[[[ComponentNamespace]]].Utilities.UserHelper", "namespace": "[[[NamespacePrefix]]]\\Joomla\\[[[ComponentNamespace]]].Utilities.UserHelper",
"description": "Create & Update User [Save]\r\n\r\n@since 5.0.2", "description": "Create & Update User [Save]\r\n\r\n@since 5.0.2",
"licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 3rd September, 2020\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git Joomla Component Builder <https:\/\/git.vdm.dev\/joomla\/Component-Builder>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n", "licensing_template": "\/**\r\n * @package Joomla.Component.Builder\r\n *\r\n * @created 3rd September, 2020\r\n * @author Llewellyn van der Merwe <https:\/\/dev.vdm.io>\r\n * @git Joomla Component Builder <https:\/\/git.vdm.dev\/joomla\/Component-Builder>\r\n * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.\r\n * @license GNU General Public License version 2 or later; see LICENSE.txt\r\n *\/\r\n",
"head": "use Joomla\\CMS\\Factory;\r\nuse Joomla\\CMS\\Language\\Text;\r\nuse Joomla\\CMS\\User\\User;\r\nuse Joomla\\CMS\\User\\UserHelper as JoomlaUserHelper;\r\nuse Joomla\\CMS\\MVC\\Model\\BaseDatabaseModel;", "head": "use Joomla\\CMS\\Factory;\r\nuse Joomla\\CMS\\Form\\Form;\r\nuse Joomla\\CMS\\Language\\Text;\r\nuse Joomla\\CMS\\User\\User;\r\nuse Joomla\\CMS\\User\\UserHelper as JoomlaUserHelper;\r\nuse Joomla\\CMS\\MVC\\Model\\BaseDatabaseModel;",
"composer": "" "composer": ""
} }

View File

@ -14,7 +14,7 @@
interface ModelInterface #Lavender { interface ModelInterface #Lavender {
+ table(string $table) : self + table(string $table) : self
+ value(mixed $value, string $field, ...) : mixed + value(mixed $value, string $field, ...) : mixed
+ values(?array $items = null, string $field, ...) : ?array + values(?array $items, string $field, ...) : ?array
+ item(?object $item, ?string $table = null) : ?object + item(?object $item, ?string $table = null) : ?object
+ items(?array $items = null, ?string $table = null) : ?array + items(?array $items = null, ?string $table = null) : ?array
+ row(?array $item, ?string $table = null) : ?array + row(?array $item, ?string $table = null) : ?array
@ -52,7 +52,7 @@ Example: $this->items(Array, 'value_key', 'table_name');
return: ?array return: ?array
arguments: arguments:
?array $items = null ?array $items
string $field string $field
?string $table = null ?string $table = null
end note end note

View File

@ -53,7 +53,7 @@ interface ModelInterface
* @return array|null * @return array|null
* @since 3.2.0 * @since 3.2.0
*/ */
public function values(?array $items = null, string $field, ?string $table = null): ?array; public function values(?array $items, string $field, ?string $table = null): ?array;
/** /**
* Model the values of an item * Model the values of an item

View File

@ -32,7 +32,7 @@
* @return array|null * @return array|null
* @since 3.2.0 * @since 3.2.0
*/ */
public function values(?array $items = null, string $field, ?string $table = null): ?array; public function values(?array $items, string $field, ?string $table = null): ?array;
/** /**
* Model the values of an item * Model the values of an item