2026-02-04 23:31:53 +01:00
< ? php
2026-02-11 19:28:12 +01:00
namespace MintyPHP\Repository\Org ;
2026-02-04 23:31:53 +01:00
use MintyPHP\DB ;
2026-02-11 19:28:12 +01:00
use MintyPHP\Repository\Support\RepoQuery ;
2026-02-04 23:31:53 +01:00
class DepartmentRepository
{
private static function unwrap ( ? array $row ) : ? array
{
if ( ! $row ) {
return null ;
}
return $row [ 'departments' ] ? ? null ;
}
private static function unwrapList ( $rows ) : array
{
if ( ! is_array ( $rows )) {
return [];
}
$list = [];
foreach ( $rows as $row ) {
$department = $row [ 'departments' ] ? ? null ;
if ( is_array ( $department )) {
$list [] = $department ;
}
}
return $list ;
}
public static function list () : array
{
$rows = DB :: select (
2026-02-11 19:28:12 +01:00
'select id, uuid, description, code, cost_center, active, created_by, modified_by, created, modified from departments order by id desc'
2026-02-04 23:31:53 +01:00
);
return self :: unwrapList ( $rows );
}
public static function listIds () : array
{
$rows = DB :: select ( 'select id from departments' );
if ( ! is_array ( $rows )) {
return [];
}
$ids = [];
foreach ( $rows as $row ) {
$data = $row [ 'departments' ] ? ? $row ;
if ( is_array ( $data ) && isset ( $data [ 'id' ])) {
$ids [] = ( int ) $data [ 'id' ];
}
}
return array_values ( array_unique ( $ids ));
}
public static function listByTenantIds ( array $tenantIds ) : array
{
$tenantIds = array_values ( array_unique ( array_map ( 'intval' , $tenantIds )));
$tenantIds = array_filter ( $tenantIds , static fn ( $id ) => $id > 0 );
if ( ! $tenantIds ) {
return [];
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $tenantIds ), '?' ));
$rows = DB :: select (
2026-02-11 19:28:12 +01:00
'select departments.id, departments.uuid, departments.description, departments.code, departments.cost_center, departments.active, departments.created_by, departments.modified_by, departments.created, departments.modified ' .
2026-02-04 23:31:53 +01:00
'from departments departments join tenant_departments td on td.department_id = departments.id ' .
2026-02-11 19:28:12 +01:00
'where departments.active = 1 and td.tenant_id in (' . $placeholders . ') ' .
'group by departments.id, departments.uuid, departments.description, departments.code, departments.cost_center, departments.active, departments.created_by, departments.modified_by, departments.created, departments.modified ' .
2026-02-04 23:31:53 +01:00
'order by departments.description asc' ,
... array_map ( 'strval' , $tenantIds )
);
return self :: unwrapList ( $rows );
}
public static function listByIds ( array $departmentIds ) : array
{
$departmentIds = array_values ( array_unique ( array_map ( 'intval' , $departmentIds )));
$departmentIds = array_filter ( $departmentIds , static fn ( $id ) => $id > 0 );
if ( ! $departmentIds ) {
return [];
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $departmentIds ), '?' ));
$rows = DB :: select (
2026-02-11 19:28:12 +01:00
'select id, uuid, description, code, cost_center, active, created_by, modified_by, created, modified from departments where active = 1 and id in (' . $placeholders . ') order by description asc' ,
2026-02-04 23:31:53 +01:00
... array_map ( 'strval' , $departmentIds )
);
return self :: unwrapList ( $rows );
}
public static function listPaged ( array $options ) : array
{
$search = trim (( string ) ( $options [ 'search' ] ? ? '' ));
$tenant = trim (( string ) ( $options [ 'tenant' ] ? ? '' ));
2026-02-11 19:28:12 +01:00
$allowedOrder = [ 'id' , 'uuid' , 'description' , 'code' , 'cost_center' , 'active' , 'created' , 'modified' ];
[ $limit , $offset ] = RepoQuery :: sanitizeLimitOffset ( $options );
[ $order , $dir ] = RepoQuery :: sanitizeOrder ( $options , $allowedOrder );
2026-02-04 23:31:53 +01:00
$where = [];
$params = [];
2026-02-11 19:28:12 +01:00
RepoQuery :: addLikeFilter (
$where ,
$params ,
[ 'description' , 'uuid' , 'code' , 'cost_center' ],
$search
);
$activeValue = array_key_exists ( 'active' , $options ) ? $options [ 'active' ] : null ;
RepoQuery :: addEnumFilter ( $where , $params , $activeValue , [
[ 'aliases' => [ '1' , 'true' , 'active' ], 'sql' => 'departments.active = 1' ],
[ 'aliases' => [ '0' , 'false' , 'inactive' ], 'sql' => 'departments.active = 0' ],
]);
RepoQuery :: addEqualsFilter (
$where ,
$params ,
$tenant ,
" exists (select 1 from tenant_departments td join tenants t on t.id = td.tenant_id and t.status = 'active' where td.department_id = departments.id and t.uuid = ?) "
);
2026-02-04 23:31:53 +01:00
if ( ! empty ( $options [ 'tenantUserId' ])) {
$tenantUserId = ( int ) $options [ 'tenantUserId' ];
if ( $tenantUserId > 0 ) {
if ( defined ( 'TENANT_SCOPE_STRICT' ) && TENANT_SCOPE_STRICT ) {
$where [] = 'exists (select 1 from tenant_departments td ' .
" join tenants t on t.id = td.tenant_id and t.status = 'active' " .
'join user_tenants ut on ut.tenant_id = td.tenant_id ' .
'where ut.user_id = ? and td.department_id = departments.id)' ;
$params [] = ( string ) $tenantUserId ;
} else {
$where [] = '(not exists (select 1 from tenant_departments td where td.department_id = departments.id) ' .
'or exists (select 1 from tenant_departments td ' .
" join tenants t on t.id = td.tenant_id and t.status = 'active' " .
'join user_tenants ut on ut.tenant_id = td.tenant_id ' .
'where ut.user_id = ? and td.department_id = departments.id))' ;
$params [] = ( string ) $tenantUserId ;
}
}
} elseif ( array_key_exists ( 'tenantIds' , $options )) {
$tenantIds = $options [ 'tenantIds' ];
$tenantIds = is_array ( $tenantIds ) ? array_values ( array_unique ( array_map ( 'intval' , $tenantIds ))) : [];
if ( $tenantIds ) {
if ( defined ( 'TENANT_SCOPE_STRICT' ) && TENANT_SCOPE_STRICT ) {
$where [] = 'exists (select 1 from tenant_departments td where td.department_id = departments.id and td.tenant_id in (???))' ;
$params [] = $tenantIds ;
} else {
$where [] = '(not exists (select 1 from tenant_departments td where td.department_id = departments.id) ' .
'or exists (select 1 from tenant_departments td where td.department_id = departments.id and td.tenant_id in (???)))' ;
$params [] = $tenantIds ;
}
} else {
if ( defined ( 'TENANT_SCOPE_STRICT' ) && TENANT_SCOPE_STRICT ) {
$where [] = '1=0' ;
} else {
$where [] = 'not exists (select 1 from tenant_departments td where td.department_id = departments.id)' ;
}
}
}
$whereSql = $where ? ( ' where ' . implode ( ' and ' , $where )) : '' ;
$count = DB :: selectValue ( 'select count(*) from departments' . $whereSql , ... $params );
$total = $count ? ( int ) $count : 0 ;
2026-02-11 19:28:12 +01:00
$query = 'select id, uuid, description, code, cost_center, active, created_by, modified_by, created, modified from departments' .
2026-02-04 23:31:53 +01:00
$whereSql .
sprintf ( ' order by `%s` %s limit ? offset ?' , $order , $dir );
$queryParams = array_merge ( $params , [( string ) $limit , ( string ) $offset ]);
$rows = call_user_func_array ([ 'MintyPHP\\DB' , 'select' ], array_merge ([ $query ], $queryParams ));
$list = self :: unwrapList ( $rows );
$ids = [];
foreach ( $list as $department ) {
if ( isset ( $department [ 'id' ])) {
$ids [] = ( int ) $department [ 'id' ];
}
}
$tenantLabelsByDepartment = [];
if ( $ids ) {
$placeholders = implode ( ',' , array_fill ( 0 , count ( $ids ), '?' ));
$labelRows = DB :: select (
" select td.department_id as department_id, t.description as description from tenant_departments td join tenants t on t.id = td.tenant_id and t.status = 'active' " .
'where td.department_id in (' . $placeholders . ') order by t.description asc' ,
... array_map ( 'strval' , $ids )
);
$collectLabels = static function ( array $rows ) : array {
$labelsByDepartment = [];
foreach ( $rows as $row ) {
$departmentId = 0 ;
$label = '' ;
if ( isset ( $row [ 'td' ]) && is_array ( $row [ 'td' ])) {
$departmentId = ( int ) ( $row [ 'td' ][ 'department_id' ] ? ? 0 );
}
if ( isset ( $row [ 't' ]) && is_array ( $row [ 't' ])) {
$label = ( string ) ( $row [ 't' ][ 'description' ] ? ? '' );
}
if ( $departmentId === 0 || $label === '' ) {
foreach ( $row as $value ) {
if ( ! is_array ( $value )) {
continue ;
}
if ( $departmentId === 0 && isset ( $value [ 'department_id' ])) {
$departmentId = ( int ) $value [ 'department_id' ];
}
if ( $label === '' && isset ( $value [ 'description' ])) {
$label = ( string ) $value [ 'description' ];
}
}
}
if ( $departmentId === 0 && isset ( $row [ 'department_id' ])) {
$departmentId = ( int ) $row [ 'department_id' ];
}
if ( $label === '' && isset ( $row [ 'description' ])) {
$label = ( string ) $row [ 'description' ];
}
if ( $departmentId > 0 && $label !== '' ) {
$labelsByDepartment [ $departmentId ] ? ? = [];
$labelsByDepartment [ $departmentId ][] = $label ;
}
}
return $labelsByDepartment ;
};
$tenantLabelsByDepartment = $collectLabels ( $labelRows );
}
foreach ( $list as & $department ) {
$departmentId = ( int ) ( $department [ 'id' ] ? ? 0 );
$department [ 'tenant_labels' ] = $tenantLabelsByDepartment [ $departmentId ] ? ? [];
}
unset ( $department );
return [
'total' => $total ,
'rows' => $list ,
];
}
public static function find ( int $id ) : ? array
{
$row = DB :: selectOne (
2026-02-11 19:28:12 +01:00
'select id, uuid, description, code, cost_center, active, created_by, modified_by, created, modified from departments where id = ? limit 1' ,
2026-02-04 23:31:53 +01:00
( string ) $id
);
return self :: unwrap ( $row );
}
public static function findByUuid ( string $uuid ) : ? array
{
$row = DB :: selectOne (
2026-02-11 19:28:12 +01:00
'select id, uuid, description, code, cost_center, active, created_by, modified_by, created, modified from departments where uuid = ? limit 1' ,
2026-02-04 23:31:53 +01:00
$uuid
);
return self :: unwrap ( $row );
}
2026-02-11 19:28:12 +01:00
public static function existsByCode ( string $code , int $excludeId = 0 ) : bool
{
$code = trim ( $code );
if ( $code === '' ) {
return false ;
}
if ( $excludeId > 0 ) {
$count = DB :: selectValue ( 'select count(*) from departments where code = ? and id != ?' , $code , ( string ) $excludeId );
} else {
$count = DB :: selectValue ( 'select count(*) from departments where code = ?' , $code );
}
return ( int ) $count > 0 ;
}
2026-02-04 23:31:53 +01:00
private static function uuidV4 () : string
{
$data = random_bytes ( 16 );
$data [ 6 ] = chr (( ord ( $data [ 6 ]) & 0x0f ) | 0x40 );
$data [ 8 ] = chr (( ord ( $data [ 8 ]) & 0x3f ) | 0x80 );
return vsprintf ( '%s%s-%s-%s-%s-%s%s%s' , str_split ( bin2hex ( $data ), 4 ));
}
public static function create ( array $data )
{
return DB :: insert (
2026-02-11 19:28:12 +01:00
'insert into departments (uuid, description, code, cost_center, active, created_by, created) values (?,?,?,?,?,?,NOW())' ,
2026-02-04 23:31:53 +01:00
$data [ 'uuid' ] ? ? self :: uuidV4 (),
$data [ 'description' ],
2026-02-11 19:28:12 +01:00
$data [ 'code' ] ? ? null ,
$data [ 'cost_center' ] ? ? null ,
$data [ 'active' ] ? ? 1 ,
2026-02-04 23:31:53 +01:00
$data [ 'created_by' ] ? ? null
);
}
public static function update ( int $id , array $data ) : bool
{
$fields = [
'description' => $data [ 'description' ],
2026-02-11 19:28:12 +01:00
'code' => $data [ 'code' ] ? ? null ,
'cost_center' => $data [ 'cost_center' ] ? ? null ,
'active' => $data [ 'active' ] ? ? 1 ,
2026-02-04 23:31:53 +01:00
];
if ( array_key_exists ( 'modified_by' , $data )) {
$fields [ 'modified_by' ] = $data [ 'modified_by' ];
}
$setParts = [];
$params = [];
foreach ( $fields as $field => $value ) {
$setParts [] = sprintf ( '`%s` = ?' , $field );
$params [] = $value ;
}
$params [] = ( string ) $id ;
$query = 'update departments set ' . implode ( ', ' , $setParts ) . ' where id = ?' ;
$result = DB :: update ( $query , ... $params );
return $result !== false ;
}
public static function delete ( int $id ) : bool
{
$result = DB :: delete ( 'delete from departments where id = ?' , ( string ) $id );
return $result !== false ;
}
}