2026-02-23 12:58:19 +01:00
< ? php
namespace MintyPHP\Repository\User ;
use MintyPHP\DB ;
use MintyPHP\Repository\Support\RepoQuery ;
2026-03-13 21:58:51 +01:00
/** Creates and mutates user records including activation, tenant links, and preferences. */
2026-03-05 08:26:51 +01:00
class UserWriteRepository implements UserWriteRepositoryInterface
2026-02-23 12:58:19 +01:00
{
public function updateLastLogin ( int $userId , string $provider = 'local' ) : void
{
if ( $userId <= 0 ) {
return ;
}
$provider = trim ( strtolower ( $provider ));
if ( ! in_array ( $provider , [ 'local' , 'microsoft' ], true )) {
$provider = 'local' ;
}
DB :: query ( 'update users set last_login_at = UTC_TIMESTAMP(), last_login_provider = ? where id = ?' , $provider , ( string ) $userId );
}
public function bumpAuthzVersion ( int $userId ) : bool
{
if ( $userId <= 0 ) {
return false ;
}
$result = DB :: update (
'update users set authz_version = authz_version + 1 where id = ?' ,
( string ) $userId
);
return $result !== false ;
}
public function bumpAuthzVersionByUserIds ( array $userIds ) : int
{
$userIds = array_values ( array_unique ( array_map ( 'intval' , $userIds )));
$userIds = array_values ( array_filter ( $userIds , static fn ( $id ) => $id > 0 ));
if ( ! $userIds ) {
return 0 ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $userIds ), '?' ));
$result = DB :: update (
" update users set authz_version = authz_version + 1 where id in ( $placeholders ) " ,
... array_map ( 'strval' , $userIds )
);
return $result !== false ? ( int ) $result : 0 ;
}
public function create ( array $data ) : int | false
{
$hash = password_hash ( $data [ 'password' ], PASSWORD_DEFAULT );
return DB :: insert (
'insert into users (uuid, first_name, last_name, display_name, email, profile_description, job_title, phone, mobile, short_dial, address, postal_code, city, country, region, hire_date, password, locale, totp_secret, theme, primary_tenant_id, current_tenant_id, created_by, created, active, active_changed_at, active_changed_by) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),?,?,?)' ,
$data [ 'uuid' ] ? ? RepoQuery :: uuidV4 (),
$data [ 'first_name' ],
$data [ 'last_name' ],
$this -> buildDisplayName ( $data ),
$data [ 'email' ],
$data [ 'profile_description' ] ? ? null ,
$data [ 'job_title' ] ? ? null ,
$data [ 'phone' ] ? ? null ,
$data [ 'mobile' ] ? ? null ,
$data [ 'short_dial' ] ? ? null ,
$data [ 'address' ] ? ? null ,
$data [ 'postal_code' ] ? ? null ,
$data [ 'city' ] ? ? null ,
$data [ 'country' ] ? ? null ,
$data [ 'region' ] ? ? null ,
$data [ 'hire_date' ] ? ? null ,
$hash ,
$data [ 'locale' ] ? ? null ,
$data [ 'totp_secret' ],
$data [ 'theme' ] ? ? 'light' ,
$data [ 'primary_tenant_id' ] ? ? null ,
$data [ 'current_tenant_id' ] ? ? $data [ 'primary_tenant_id' ] ? ? null ,
$data [ 'created_by' ] ? ? null ,
$data [ 'active' ],
$data [ 'active_changed_at' ] ? ? null ,
$data [ 'active_changed_by' ] ? ? null
);
}
public function update ( int $id , array $data ) : bool
{
$fields = [
'first_name' => $data [ 'first_name' ],
'last_name' => $data [ 'last_name' ],
'display_name' => $this -> buildDisplayName ( $data ),
'email' => $data [ 'email' ],
'profile_description' => $data [ 'profile_description' ] ? ? null ,
'job_title' => $data [ 'job_title' ] ? ? null ,
'phone' => $data [ 'phone' ] ? ? null ,
'mobile' => $data [ 'mobile' ] ? ? null ,
'short_dial' => $data [ 'short_dial' ] ? ? null ,
'address' => $data [ 'address' ] ? ? null ,
'postal_code' => $data [ 'postal_code' ] ? ? null ,
'city' => $data [ 'city' ] ? ? null ,
'country' => $data [ 'country' ] ? ? null ,
'region' => $data [ 'region' ] ? ? null ,
'hire_date' => $data [ 'hire_date' ] ? ? null ,
'totp_secret' => $data [ 'totp_secret' ],
'active' => $data [ 'active' ],
];
if ( array_key_exists ( 'locale' , $data )) {
$fields [ 'locale' ] = $data [ 'locale' ];
}
if ( array_key_exists ( 'theme' , $data )) {
$fields [ 'theme' ] = $data [ 'theme' ];
}
if ( array_key_exists ( 'primary_tenant_id' , $data )) {
$fields [ 'primary_tenant_id' ] = $data [ 'primary_tenant_id' ];
}
if ( array_key_exists ( 'current_tenant_id' , $data )) {
$fields [ 'current_tenant_id' ] = $data [ 'current_tenant_id' ];
}
if ( array_key_exists ( 'modified_by' , $data )) {
$fields [ 'modified_by' ] = $data [ 'modified_by' ];
}
if ( array_key_exists ( 'active_changed_at' , $data )) {
$fields [ 'active_changed_at' ] = $data [ 'active_changed_at' ];
}
if ( array_key_exists ( 'active_changed_by' , $data )) {
$fields [ 'active_changed_by' ] = $data [ 'active_changed_by' ];
}
if ( ! empty ( $data [ 'password' ])) {
$fields [ 'password' ] = password_hash ( $data [ 'password' ], PASSWORD_DEFAULT );
}
$setParts = [];
$params = [];
foreach ( $fields as $field => $value ) {
$setParts [] = sprintf ( '`%s` = ?' , $field );
$params [] = $value ;
}
$params [] = ( string ) $id ;
$query = 'update users set ' . implode ( ', ' , $setParts ) . ' where id = ?' ;
$result = DB :: update ( $query , ... $params );
return $result !== false ;
}
public function setActive ( int $id , bool $active , ? int $changedBy = null ) : bool
{
$result = DB :: update (
'update users set active = ?, active_changed_at = NOW(), active_changed_by = ? where id = ?' ,
$active ? 1 : 0 ,
$changedBy ,
( string ) $id
);
return $result !== false ;
}
public function setCurrentTenant ( int $id , int $tenantId ) : bool
{
$result = DB :: update (
'update users set current_tenant_id = ? where id = ?' ,
( string ) $tenantId ,
( string ) $id
);
return $result !== false ;
}
public function setActiveByUuids ( array $uuids , bool $active , ? int $modifiedBy = null ) : bool
{
$uuids = array_values ( array_filter ( array_map ( 'trim' , $uuids )));
if ( ! $uuids ) {
return false ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $uuids ), '?' ));
$query = " update users set active = ?, modified_by = ?, active_changed_at = NOW(), active_changed_by = ? where uuid in ( $placeholders ) " ;
$params = array_merge ([ $active ? 1 : 0 , $modifiedBy , $modifiedBy ], $uuids );
$result = DB :: update ( $query , ... $params );
return $result !== false ;
}
public function setInactiveByIds ( array $userIds , ? int $changedBy = null ) : int
{
$ids = array_values ( array_unique ( array_filter ( array_map ( 'intval' , $userIds ), static fn ( $id ) => $id > 0 )));
if ( ! $ids ) {
return 0 ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $ids ), '?' ));
$query = " update users set active = 0, modified_by = ?, active_changed_at = UTC_TIMESTAMP(), active_changed_by = ? where active = 1 and id in ( $placeholders ) " ;
$params = array_merge ([ $changedBy , $changedBy ], array_map ( 'strval' , $ids ));
$result = DB :: update ( $query , ... $params );
return $result !== false ? ( int ) $result : 0 ;
}
public function deleteByIds ( array $userIds ) : int
{
$ids = array_values ( array_unique ( array_filter ( array_map ( 'intval' , $userIds ), static fn ( $id ) => $id > 0 )));
if ( ! $ids ) {
return 0 ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $ids ), '?' ));
$result = DB :: delete (
" delete from users where id in ( $placeholders ) " ,
... array_map ( 'strval' , $ids )
);
return $result !== false ? ( int ) $result : 0 ;
}
public function setLocale ( int $id , string $locale ) : bool
{
$result = DB :: update ( 'update users set locale = ? where id = ?' , $locale , ( string ) $id );
return $result !== false ;
}
public function setTheme ( int $id , string $theme ) : bool
{
$result = DB :: update ( 'update users set theme = ? where id = ?' , $theme , ( string ) $id );
return $result !== false ;
}
public function updateProfileFieldsFromSso ( int $id , array $fields ) : bool
{
if ( $id <= 0 ) {
return false ;
}
2026-04-13 14:13:21 +02:00
$row = DB :: selectOne ( 'select first_name, last_name, email, phone, mobile, job_title, display_name from users where id = ? limit 1' , ( string ) $id );
2026-02-23 12:58:19 +01:00
$existing = $row [ 'users' ] ? ? null ;
if ( ! is_array ( $existing )) {
return false ;
}
2026-04-13 14:13:21 +02:00
$allowed = [ 'first_name' , 'last_name' , 'display_name' , 'job_title' , 'phone' , 'mobile' ];
2026-02-23 12:58:19 +01:00
$updates = [];
foreach ( $allowed as $field ) {
if ( ! array_key_exists ( $field , $fields )) {
continue ;
}
$value = trim (( string ) $fields [ $field ]);
if ( $value === '' ) {
continue ;
}
if (( string ) ( $existing [ $field ] ? ? '' ) === $value ) {
continue ;
}
$updates [ $field ] = $value ;
}
if ( ! $updates ) {
return true ;
}
2026-04-13 14:13:21 +02:00
if ( ! isset ( $updates [ 'display_name' ]) && ( isset ( $updates [ 'first_name' ]) || isset ( $updates [ 'last_name' ]))) {
2026-02-23 12:58:19 +01:00
$displayData = [
'first_name' => $updates [ 'first_name' ] ? ? ( string ) ( $existing [ 'first_name' ] ? ? '' ),
'last_name' => $updates [ 'last_name' ] ? ? ( string ) ( $existing [ 'last_name' ] ? ? '' ),
'email' => ( string ) ( $existing [ 'email' ] ? ? '' ),
];
$updates [ 'display_name' ] = $this -> buildDisplayName ( $displayData );
}
$setParts = [];
$params = [];
foreach ( $updates as $field => $value ) {
$setParts [] = sprintf ( '`%s` = ?' , $field );
$params [] = $value ;
}
$params [] = ( string ) $id ;
$result = DB :: update (
'update users set ' . implode ( ', ' , $setParts ) . ' where id = ?' ,
... $params
);
return $result !== false ;
}
public function setPassword ( int $id , string $password ) : bool
{
$hash = password_hash ( $password , PASSWORD_DEFAULT );
$result = DB :: update ( 'update users set password = ?, modified_by = NULL where id = ?' , $hash , ( string ) $id );
return $result !== false ;
}
public function setEmailVerified ( int $id ) : bool
{
$result = DB :: update ( 'update users set email_verified_at = NOW() where id = ?' , ( string ) $id );
return $result !== false ;
}
public function delete ( int $id ) : bool
{
$result = DB :: delete ( 'delete from users where id = ?' , ( string ) $id );
return $result !== false ;
}
public function deleteByUuids ( array $uuids ) : bool
{
$uuids = array_values ( array_filter ( array_map ( 'trim' , $uuids )));
if ( ! $uuids ) {
return false ;
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $uuids ), '?' ));
$query = " delete from users where uuid in ( $placeholders ) " ;
$result = DB :: delete ( $query , ... $uuids );
return $result !== false ;
}
private function buildDisplayName ( array $data ) : string
{
$first = trim (( string ) ( $data [ 'first_name' ] ? ? '' ));
$last = trim (( string ) ( $data [ 'last_name' ] ? ? '' ));
$name = trim ( $first . ' ' . $last );
if ( $name === '' ) {
$name = trim (( string ) ( $data [ 'email' ] ? ? '' ));
}
return $name ;
}
}