Release of v5.0.3-alpha4
Fix database default fields to allow NULL. #1169. Fix the power list field to allow search. #1167. Expanded the Demo component in JCB v4 to include more advance features.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 3rd September, 2020
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Utilities\Exception;
|
||||
|
||||
|
||||
/**
|
||||
* No User Id Found Exception
|
||||
*
|
||||
* @since 5.0.2
|
||||
*/
|
||||
class NoUserIdFoundException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,481 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 3rd September, 2020
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\User\User;
|
||||
use Joomla\CMS\User\UserHelper as JoomlaUserHelper;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use VDM\Joomla\Utilities\Component\Helper as Component;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Componentbuilder\Utilities\Exception\NoUserIdFoundException;
|
||||
use VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Create & Update User [Save]
|
||||
*
|
||||
* @since 5.0.2
|
||||
*/
|
||||
abstract class UserHelper
|
||||
{
|
||||
/**
|
||||
* Save user details by either creating a new user or updating an existing user.
|
||||
*
|
||||
* @param array $credentials User credentials including 'name', 'username', 'email', 'password', and 'password2'.
|
||||
* @param int $autologin Flag to determine whether to auto-login the user after registration.
|
||||
* @param array $params Parameters for user activation, password sending, and user registration allowance.
|
||||
* @param int $mode Mode of registration: 1 = Site Registration, 0 = Admin Registration, 2 = Custom Helper Method.
|
||||
*
|
||||
* @return int User ID on success.
|
||||
*
|
||||
* @throws \InvalidArgumentException If required credentials are missing.
|
||||
* @throws \RuntimeException If the user update or creation fails.
|
||||
* @throws NoUserIdFoundException If the user is not found.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static function save(array $credentials, int $autologin = 0,
|
||||
array $params = ['useractivation' => 0, 'sendpassword' => 1], int $mode = 1): int
|
||||
{
|
||||
// can not continue without an email
|
||||
if (empty($credentials['email']))
|
||||
{
|
||||
throw new \InvalidArgumentException(Text::_('COM_COMPONENTBUILDER_CAN_NOT_SAVE_USER_WITHOUT_EMAIL_VALUE'));
|
||||
}
|
||||
|
||||
// Ensure the 'username' key exists in the credentials array, set to an empty string if not provided.
|
||||
$username = $credentials['username'] ?? $credentials['email'];
|
||||
|
||||
// If the user's ID is set and valid, handle the update logic.
|
||||
if (!empty($credentials['id']) && $credentials['id'] > 0)
|
||||
{
|
||||
$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 (
|
||||
($existingEmailUserId && $existingEmailUserId != $userId) ||
|
||||
($existingUsernameId && $existingUsernameId != $userId) ||
|
||||
($existingEmailUserId && $existingUsernameId && $existingEmailUserId != $existingUsernameId)
|
||||
) {
|
||||
throw new NoUserIdFoundException(
|
||||
Text::sprintf(
|
||||
'User ID mismatch detected when trying to save %s (%s) credentials.',
|
||||
$username,
|
||||
$email
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Update the existing user.
|
||||
return static::update($credentials);
|
||||
}
|
||||
|
||||
// Create a new user if no existing user is found.
|
||||
return static::create($credentials, $autologin, $params, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user and update the given table.
|
||||
*
|
||||
* @param array $credentials User credentials including 'name', 'username', 'email', 'password', and 'password2'.
|
||||
* @param int $autologin Flag to determine whether to auto-login the user after registration.
|
||||
* @param array $params Parameters for user activation, password sending, and user registration allowance.
|
||||
* @param int $mode Mode of registration: 1 = Site Registration, 0 = Admin Registration, 2 = Custom Helper Method.
|
||||
*
|
||||
* @return int User ID on success.
|
||||
*
|
||||
* @throws \RuntimeException If user creation fails.
|
||||
* @throws NoUserIdFoundException If the user is not found.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static function create(array $credentials, int $autologin = 0,
|
||||
array $params = ['useractivation' => 0, 'sendpassword' => 1], int $mode = 1): int
|
||||
{
|
||||
$lang = Factory::getLanguage();
|
||||
$lang->load('com_users', JPATH_SITE, 'en-GB', true);
|
||||
|
||||
// Handle custom registration mode
|
||||
if ($mode === 2 && method_exists(ComponentbuilderHelper::class, 'registerUser'))
|
||||
{
|
||||
$params['autologin'] = $autologin;
|
||||
$userId = ComponentbuilderHelper::registerUser($credentials, $params);
|
||||
|
||||
if (is_numeric($userId))
|
||||
{
|
||||
return $userId;
|
||||
}
|
||||
|
||||
throw new NoUserIdFoundException(Text::_('COM_COMPONENTBUILDER_USER_CREATION_FAILED'));
|
||||
}
|
||||
|
||||
// Check if we have params/config
|
||||
if (ArrayHelper::check($params))
|
||||
{
|
||||
// Make changes to user config
|
||||
foreach ($params as $param => $set)
|
||||
{
|
||||
// If you know of a better path, let me know
|
||||
$params[$param] = Component::setParams($param, $set, 'com_users');
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to Site Registrations if mode is set to 2 but the method doesn't exist
|
||||
$mode = $mode === 2 ? 1 : $mode;
|
||||
|
||||
// Load the appropriate user model
|
||||
$model = static::getModelByMode($mode);
|
||||
|
||||
// Set default values for missing credentials
|
||||
$credentials['username'] = $credentials['username'] ?? $credentials['email'];
|
||||
|
||||
// Prepare user data
|
||||
$data = static::prepareUserData($credentials, $mode);
|
||||
|
||||
// Set form path (bug fix for Joomla)
|
||||
static::setFormPathForUserClass($mode);
|
||||
|
||||
// Handle user creation
|
||||
$userId = $mode === 1 ? $model->register($data) : static::adminRegister($model, $data);
|
||||
|
||||
// Check if we have params
|
||||
if (ArrayHelper::check($params))
|
||||
{
|
||||
// Change user params/config back
|
||||
foreach ($params as $param => $set)
|
||||
{
|
||||
// If you know of a better path, let me know
|
||||
Component::setParams($param, $set, 'com_users');
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Handle post-registration processes
|
||||
return static::handlePostRegistration($userId, $autologin, $credentials);
|
||||
}
|
||||
|
||||
$error_messages = '';
|
||||
if (method_exists($model, 'getError'))
|
||||
{
|
||||
$errors = $model->getError();
|
||||
if (!empty($errors))
|
||||
{
|
||||
if (is_array($errors))
|
||||
{
|
||||
$error_messages = '<br>' . implode('<br>', $errors);
|
||||
}
|
||||
elseif (is_string($errors))
|
||||
{
|
||||
$error_messages = '<br>' . $errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoUserIdFoundException(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_USER_S_S_CREATION_FAILEDS',
|
||||
(string) $credentials['username'],
|
||||
(string) $credentials['email'],
|
||||
$error_messages
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user details.
|
||||
*
|
||||
* @param array $userDetails Array containing user details to be updated.
|
||||
*
|
||||
* @return int Updated user ID on success.
|
||||
*
|
||||
* @throws \RuntimeException If user update fails.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static function update(array $userDetails): int
|
||||
{
|
||||
$lang = Factory::getLanguage();
|
||||
$lang->load('com_users', JPATH_ADMINISTRATOR, 'en-GB', true);
|
||||
|
||||
$model = Component::getModel('User', 'Administrator', 'com_users');
|
||||
|
||||
// Set default values for missing credentials
|
||||
$userDetails['username'] = $userDetails['username'] ?? $userDetails['email'];
|
||||
|
||||
// Prepare user data for update
|
||||
$data = [
|
||||
'id' => $userDetails['id'],
|
||||
'username' => $userDetails['username'],
|
||||
'name' => $userDetails['name'],
|
||||
'email' => $userDetails['email'],
|
||||
'password' => $userDetails['password'] ?? null,
|
||||
'password2' => $userDetails['password2'] ?? null,
|
||||
'block' => 0
|
||||
];
|
||||
|
||||
// set groups if found
|
||||
if (isset($userDetails['groups']) && ArrayHelper::check($userDetails['groups']))
|
||||
{
|
||||
$data['groups'] = $userDetails['groups'];
|
||||
}
|
||||
|
||||
// Update the user
|
||||
if ($model->save($data))
|
||||
{
|
||||
return $userDetails['id'];
|
||||
}
|
||||
|
||||
$error_messages = '';
|
||||
if (method_exists($model, 'getError'))
|
||||
{
|
||||
$errors = $model->getError();
|
||||
if (!empty($errors))
|
||||
{
|
||||
if (is_array($errors))
|
||||
{
|
||||
$error_messages = '<br>' . implode('<br>', $errors);
|
||||
}
|
||||
elseif (is_string($errors))
|
||||
{
|
||||
$error_messages = '<br>' . $errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_UPDATE_OF_USER_S_S_FAILEDS',
|
||||
(string) $userDetails['username'],
|
||||
(string) $userDetails['email'],
|
||||
(string) $error_messages
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get an instance of a user for the given id.
|
||||
*
|
||||
* @param int $id The id
|
||||
*
|
||||
* @return User
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static function getUserById(int $id): User
|
||||
{
|
||||
return new User($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user ID by username.
|
||||
*
|
||||
* @param string $username The username to check.
|
||||
*
|
||||
* @return int|null The user ID if the user exists, null otherwise.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static function getUserIdByUsername(string $username): ?int
|
||||
{
|
||||
$userId = JoomlaUserHelper::getUserId($username);
|
||||
return $userId ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user ID by email.
|
||||
*
|
||||
* @param string $email The email address to check.
|
||||
*
|
||||
* @return int|null The user ID if the user exists, null otherwise.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public static function getUserIdByEmail(string $email): ?int
|
||||
{
|
||||
// Initialise some variables
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__users'))
|
||||
->where($db->quoteName('email') . ' = :email')
|
||||
->bind(':email', $email)
|
||||
->setLimit(1);
|
||||
$db->setQuery($query);
|
||||
|
||||
$userId = $db->loadResult();
|
||||
return $userId ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the correct user model based on the registration mode.
|
||||
*
|
||||
* @param int $mode The registration mode.
|
||||
*
|
||||
* @return BaseDatabaseModel The appropriate user model.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected static function getModelByMode(int $mode): BaseDatabaseModel
|
||||
{
|
||||
if ($mode === 1)
|
||||
{
|
||||
return Component::getModel('Registration', 'Site', 'com_users');
|
||||
}
|
||||
|
||||
return Component::getModel('User', 'Administrator', 'com_users');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare user data array for registration or update.
|
||||
*
|
||||
* @param array $credentials User credentials.
|
||||
* @param int $mode The registration mode.
|
||||
*
|
||||
* @return array The prepared user data array.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected static function prepareUserData(array $credentials, int $mode)
|
||||
{
|
||||
$data = [
|
||||
'username' => $credentials['username'],
|
||||
'name' => $credentials['name'],
|
||||
'block' => 0
|
||||
];
|
||||
|
||||
if ($mode === 1)
|
||||
{
|
||||
$data['email1'] = $credentials['email'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['email'] = $credentials['email'];
|
||||
$data['registerDate'] = Factory::getDate()->toSql();
|
||||
}
|
||||
|
||||
if ($mode === 1 && empty($credentials['password']))
|
||||
{
|
||||
$credentials['password'] = StringHelper::random(10);
|
||||
$credentials['password2'] = $credentials['password'];
|
||||
}
|
||||
|
||||
if (!empty($credentials['password']) && !empty($credentials['password2']))
|
||||
{
|
||||
$data['password1'] = $credentials['password'];
|
||||
$data['password2'] = $credentials['password2'];
|
||||
}
|
||||
|
||||
if ($mode === 0 && isset($credentials['groups']) && ArrayHelper::check($credentials['groups']))
|
||||
{
|
||||
$data['groups'] = $credentials['groups'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the registration process for admin mode.
|
||||
*
|
||||
* @param BaseDatabaseModel $model The user model.
|
||||
* @param array $data The user data.
|
||||
*
|
||||
* @return int The ID of the created user.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
private static function adminRegister(BaseDatabaseModel $model, array $data): int
|
||||
{
|
||||
$model->save($data);
|
||||
|
||||
return $model->getState('user.id', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle post-registration processes like auto-login.
|
||||
*
|
||||
* @param int $userId The ID of the created user.
|
||||
* @param int $autologin Flag to determine whether to auto-login the user.
|
||||
* @param array $credentials The user credentials.
|
||||
*
|
||||
* @return int The user ID on success.
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
private static function handlePostRegistration(int $userId, int $autologin, array $credentials): int
|
||||
{
|
||||
// make sure user is it the correct groups
|
||||
if ($userId > 0 && !empty($credentials['groups']))
|
||||
{
|
||||
try
|
||||
{
|
||||
JoomlaUserHelper::setUserGroups($userId, $credentials['groups']);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
// we might need say something
|
||||
}
|
||||
}
|
||||
|
||||
if ($autologin && !empty($credentials['password']))
|
||||
{
|
||||
try
|
||||
{
|
||||
Factory::getApplication()->login($credentials);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
// we might need to redirect here?
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user