make id public, organigram impl. media password/encryption, settings bug fix, Money->FloatInt change, ...

This commit is contained in:
Dennis Eichhorn 2023-05-06 11:42:06 +00:00
parent c81bae26cf
commit 9edbe6cc4b
53 changed files with 1076 additions and 397 deletions

View File

@ -37,7 +37,7 @@ class Account implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Names.
@ -69,7 +69,7 @@ class Account implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $email = '';
public string $email = '';
/**
* Ip.
@ -79,7 +79,7 @@ class Account implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $origin = '';
public string $origin = '';
/**
* Login.
@ -95,7 +95,7 @@ class Account implements \JsonSerializable
* @var \DateTime
* @since 1.0.0
*/
protected \DateTime $lastActive;
public \DateTime $lastActive;
/**
* Last activity.
@ -111,7 +111,7 @@ class Account implements \JsonSerializable
* @var Group[]
* @since 1.0.0
*/
protected array $groups = [];
public array $groups = [];
/**
* Password.
@ -119,7 +119,7 @@ class Account implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $password = '';
public string $password = '';
/**
* Account type.
@ -127,7 +127,7 @@ class Account implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $type = AccountType::USER;
public int $type = AccountType::USER;
/**
* Account status.
@ -135,7 +135,7 @@ class Account implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $status = AccountStatus::INACTIVE;
public int $status = AccountStatus::INACTIVE;
/**
* Localization.
@ -147,6 +147,31 @@ class Account implements \JsonSerializable
use PermissionHandlingTrait;
public function hasPermission(
int $permission,
int $unit = null,
int $app = null,
string $module = null,
int $category = null,
int $element = null,
int $component = null
) : bool
{
foreach ($this->groups as $group) {
if ($group->hasPermission($permission, $unit, $app, $module, $category, $element, $component)) {
return true;
}
}
foreach ($this->permissions as $p) {
if ($p->hasPermission($permission, $unit, $app, $module, $category, $element, $component)) {
return true;
}
}
return false;
}
/**
* Constructor.
*
@ -203,7 +228,7 @@ class Account implements \JsonSerializable
/*
$ids = [];
foreach ($this->groups as $group) {
$ids[] = $group->getId();
$ids[] = $group->id;
}
return $ids;
@ -237,7 +262,7 @@ class Account implements \JsonSerializable
public function hasGroup(int $id) : bool
{
foreach ($this->groups as $group) {
if ($group->getId() === $id) {
if ($group->id === $id) {
return true;
}
}

View File

@ -32,7 +32,7 @@ class Group implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Group name.
@ -56,7 +56,7 @@ class Group implements \JsonSerializable
* @var array
* @since 1.0.0
*/
protected array $members = [];
public array $members = [];
/**
* Parents.
@ -64,7 +64,7 @@ class Group implements \JsonSerializable
* @var int[]
* @since 1.0.0
*/
protected array $parents = [];
public array $parents = [];
/**
* Group status.
@ -72,7 +72,7 @@ class Group implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $status = GroupStatus::INACTIVE;
public int $status = GroupStatus::INACTIVE;
use PermissionHandlingTrait;

View File

@ -33,7 +33,7 @@ class PermissionAbstract implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Unit id.

View File

@ -30,7 +30,7 @@ trait PermissionHandlingTrait
* @var PermissionAbstract[]
* @since 1.0.0
*/
protected array $permissions = [];
public array $permissions = [];
/**
* Set permissions.

View File

@ -118,7 +118,7 @@ final class Autoloader
foreach (self::$paths as $path) {
if (\is_file($file = $path . $class . '.php')) {
include $file;
include_once $file;
return;
}

View File

@ -193,10 +193,17 @@ abstract class GrammarAbstract
$expression = '';
foreach ($elements as $key => $element) {
if (\is_string($element) && $element !== '*') {
$expression .= $this->compileSystem($element) . (\is_string($key) ? ' as ' . $key : '') . ', ';
} elseif ($element === '*') {
$expression .= '*, ';
if (\is_string($element)) {
// @note: Replaced $this->compileSystem with $element
// This causes problems for tables or columns which use keywords such as count,
// but they are rare and should be handled somewhere else if it actually is such a case
if (\in_array($element, ['group', 'id', 'where', 'order'])) {
$expression .= $this->compileSystem($element)
. (\is_string($key) ? ' as ' . $key : '') . ', ';
} else {
$expression .= $element
. (\is_string($key) ? ' as ' . $key : '') . ', ';
}
} elseif ($element instanceof \Closure) {
$expression .= $element() . (\is_string($key) ? ' as ' . $key : '') . ', ';
} elseif ($element instanceof BuilderAbstract) {
@ -226,7 +233,7 @@ abstract class GrammarAbstract
$identifierEnd = $this->systemIdentifierEnd;
foreach ($this->specialKeywords as $keyword) {
if (\strrpos($system, $keyword, -\strlen($system)) !== false) {
if (\stripos($system, $keyword) !== false) {
$identifierStart = '';
$identifierEnd = '';
@ -240,18 +247,25 @@ abstract class GrammarAbstract
if (($pos = \stripos($system, '.')) !== false) {
$split = [\substr($system, 0, $pos), \substr($system, $pos + 1)];
return ($split[0] !== '*' ? $identifierStart : '')
. $split[0]
. ($split[0] !== '*' ? $identifierEnd : '')
$identifierTwoStart = $identifierStart;
$identifierTwoEnd = $identifierEnd;
if ($split[1] === '*') {
$identifierTwoStart = '';
$identifierTwoEnd = '';
}
return $identifierStart . $split[0] . $identifierEnd
. '.'
. ($split[1] !== '*' ? $identifierStart : '')
. $split[1]
. ($split[1] !== '*' ? $identifierEnd : '');
. $identifierTwoStart . $split[1] . $identifierTwoEnd;
}
return ($system !== '*' ? $identifierStart : '')
. $system
. ($system !== '*' ? $identifierEnd : '');
if ($system === '*') {
$identifierStart = '';
$identifierEnd = '';
}
return $identifierStart . $system . $identifierEnd;
}
/**

View File

@ -16,6 +16,7 @@ namespace phpOMS\DataStorage\Database\Mapper;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
use phpOMS\DataStorage\Database\Query\Builder;
use phpOMS\DataStorage\Database\Query\JoinType;
use phpOMS\DataStorage\Database\Query\OrderType;
/**
@ -103,6 +104,14 @@ abstract class DataMapperAbstract
*/
protected array $join = [];
/**
* Join conditions
*
* @var array
* @since 1.0.0
*/
protected array $on = [];
/**
* Base query which is merged with the query in the mapper
*
@ -328,7 +337,7 @@ abstract class DataMapperAbstract
*
* @since 1.0.0
*/
public function join(string $member, string $mapper, mixed $value, string $logic = '=', string $type = 'left') : self
public function join(string $member, string $mapper, mixed $value, string $logic = '=', string $type = JoinType::LEFT_JOIN) : self
{
$split = \explode('/', $member);
$memberSplit = \array_shift($split);
@ -344,6 +353,19 @@ abstract class DataMapperAbstract
return $this;
}
public function on(string $member, mixed $value, string $logic = '=', string $connector = 'AND', string $relation = '') : self
{
$this->on[$relation][] = [
'child' => '',
'member' => $member,
'value' => $value,
'logic' => $logic,
'comparison' => $connector,
];
return $this;
}
/**
* Define the joining data
*
@ -358,7 +380,7 @@ abstract class DataMapperAbstract
*/
public function leftJoin(string $member, string $mapper, mixed $value, string $logic = '=') : self
{
return $this->join($member, $mapper, $value, $logic, 'left');
return $this->join($member, $mapper, $value, $logic, JoinType::LEFT_JOIN);
}
/**
@ -375,7 +397,7 @@ abstract class DataMapperAbstract
*/
public function rightJoin(string $member, string $mapper, mixed $value, string $logic = '=') : self
{
return $this->join($member, $mapper, $value, $logic, 'right');
return $this->join($member, $mapper, $value, $logic, JoinType::RIGHT_JOIN);
}
/**
@ -392,7 +414,7 @@ abstract class DataMapperAbstract
*/
public function innerJoin(string $member, string $mapper, mixed $value, string $logic = '=') : self
{
return $this->join($member, $mapper, $value, $logic, 'inner');
return $this->join($member, $mapper, $value, $logic, JoinType::INNER_JOIN);
}
/**
@ -461,6 +483,26 @@ abstract class DataMapperAbstract
}
}
if (isset($this->join[$member])) {
foreach ($this->join[$member] as $join) {
if ($join['child'] === '') {
continue;
}
$relMapper->join($join['child'], $join['mapper'], $join['value'], $join['logic'], $join['type']);
}
}
if (isset($this->on[$member])) {
foreach ($this->on[$member] as $on) {
if ($on['child'] === '') {
continue;
}
$relMapper->on($on['child'], $on['value'], $on['logic'], $on['comparison'], $on['field']);
}
}
return $relMapper;
}

View File

@ -427,28 +427,17 @@ class DataMapperFactory
* Get id of object
*
* @param object $obj Model to create
* @param \ReflectionClass $refClass Reflection class
* @param string $member Member name for the id, if it is not the primary key
*
* @return mixed
*
* @since 1.0.0
*/
public static function getObjectId(object $obj, \ReflectionClass $refClass = null, string $member = null) : mixed
public static function getObjectId(object $obj, string $member = null) : mixed
{
$refClass ??= new \ReflectionClass($obj);
$propertyName = $member ?? static::COLUMNS[static::PRIMARYFIELD]['internal'];
$refProp = $refClass->getProperty($propertyName);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$objectId = $refProp->getValue($obj);
$refProp->setAccessible(false);
} else {
$objectId = $obj->{$propertyName};
}
return $objectId;
return $obj->{$propertyName};
}
/**
@ -469,9 +458,7 @@ class DataMapperFactory
\settype($objId, static::COLUMNS[static::PRIMARYFIELD]['type']);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$refProp->setValue($obj, $objId);
$refProp->setAccessible(false);
} else {
$obj->{$propertyName} = $objId;
}
@ -615,8 +602,7 @@ class DataMapperFactory
$secondaryId
);
$cloned
->where('', $where)
$cloned->where('', $where)
->sort($primarySortField, OrderType::DESC);
}

View File

@ -72,7 +72,7 @@ final class DeleteMapper extends DataMapperAbstract
public function executeDelete(object $obj) : mixed
{
$refClass = new \ReflectionClass($obj);
$objId = $this->mapper::getObjectId($obj, $refClass);
$objId = $this->mapper::getObjectId($obj);
if (empty($objId)) {
return null;
@ -139,9 +139,7 @@ final class DeleteMapper extends DataMapperAbstract
$refProp = $refClass->getProperty($member);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$relMapper->execute($refProp->getValue($obj));
$refProp->setAccessible(false);
} else {
$relMapper->execute($obj->{$member});
}
@ -174,9 +172,7 @@ final class DeleteMapper extends DataMapperAbstract
$objIds = [];
$refProp = $refClass->getProperty($member);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$values = $refProp->getValue($obj);
$refProp->setAccessible(false);
} else {
$values = $obj->{$member};
}
@ -198,7 +194,7 @@ final class DeleteMapper extends DataMapperAbstract
continue;
}
$objIds[$key] = $mapper::getObjectId($value, $relReflectionClass);
$objIds[$key] = $mapper::getObjectId($value);
}
// delete relation tables

View File

@ -26,6 +26,9 @@ use phpOMS\Utils\ArrayUtils;
* @link https://jingga.app
* @since 1.0.0
*
* @todo Add memory cache per read mapper parent call (These should be cached: attribute types, file types, etc.)
* @todo Add getArray functions to get array instead of object
*
* @template R
*/
final class ReadMapper extends DataMapperAbstract
@ -330,20 +333,57 @@ final class ReadMapper extends DataMapperAbstract
}
/* variable in model */
// @todo: join handling is extremely ugly, needs to be refactored
foreach ($values as $join) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($join['child'] !== '') {
continue;
}
$query->join($join['mapper']::TABLE, $join['type'], $join['mapper']::TABLE . '_d' . ($this->depth + 1))
->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $col,
'=',
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::getColumnByMember($join['value']),
'and',
$join['mapper']::TABLE . '_d' . ($this->depth + 1)
);
if (isset($join['mapper']::HAS_MANY[$join['value']])) {
if (isset($join['mapper']::HAS_MANY[$join['value']]['external'])) {
// join with relation table
$query->join($join['mapper']::HAS_MANY[$join['value']]['table'], $join['type'], $join['mapper']::HAS_MANY[$join['value']]['table'] . '_d' . ($this->depth + 1))
->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $col,
'=',
$join['mapper']::HAS_MANY[$join['value']]['table'] . '_d' . ($this->depth + 1) . '.' . $join['mapper']::HAS_MANY[$join['value']]['external'],
'AND',
$join['mapper']::HAS_MANY[$join['value']]['table'] . '_d' . ($this->depth + 1)
);
// join with model table
$query->join($join['mapper']::TABLE, $join['type'], $join['mapper']::TABLE . '_d' . ($this->depth + 1))
->on(
$join['mapper']::HAS_MANY[$join['value']]['table'] . '_d' . ($this->depth + 1) . '.' . $join['mapper']::HAS_MANY[$join['value']]['self'],
'=',
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::PRIMARYFIELD,
'AND',
$join['mapper']::TABLE . '_d' . ($this->depth + 1)
);
if (isset($this->on[$join['value']])) {
foreach ($this->on[$join['value']] as $on) {
$query->where(
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::getColumnByMember($on['member']),
'=',
$on['value'],
'AND'
);
}
}
}
} else {
$query->join($join['mapper']::TABLE, $join['type'], $join['mapper']::TABLE . '_d' . ($this->depth + 1))
->on(
$this->mapper::TABLE . '_d' . $this->depth . '.' . $col,
'=',
$join['mapper']::TABLE . '_d' . ($this->depth + 1) . '.' . $join['mapper']::getColumnByMember($join['value']),
'AND',
$join['mapper']::TABLE . '_d' . ($this->depth + 1)
);
}
}
}
@ -356,57 +396,59 @@ final class ReadMapper extends DataMapperAbstract
continue;
}
if (($col = $this->mapper::getColumnByMember($member)) !== null) {
// In case alternative where values are allowed
// This is different from normal or conditions as these are exclusive or conditions
// This means they are only selected IFF the previous where clause fails
$alt = [];
if (($col = $this->mapper::getColumnByMember($member)) === null) {
continue;
}
/* variable in model */
$previous = null;
foreach ($values as $where) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($where['child'] !== '') {
continue;
// In case alternative where values are allowed
// This is different from normal or conditions as these are exclusive or conditions
// This means they are only selected IFF the previous where clause fails
$alt = [];
/* variable in model */
$previous = null;
foreach ($values as $where) {
// @todo: the has many, etc. if checks only work if it is a relation on the first level, if we have a deeper where condition nesting this fails
if ($where['child'] !== '') {
continue;
}
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
if ($where['comparison'] === 'ALT') {
// This uses an alternative value if the previous value(s) in the where clause don't exist (e.g. for localized results where you allow a user language, alternatively a primary language, and then alternatively any language if the first two don't exist).
// is first value
if (empty($alt)) {
$alt[] = $previous['value'];
}
$comparison = \is_array($where['value']) && \count($where['value']) > 1 ? 'in' : $where['logic'];
if ($where['comparison'] === 'ALT') {
// This uses an alternative value if the previous value(s) in the where clause don't exist (e.g. for localized results where you allow a user language, alternatively a primary language, and then alternatively any language if the first two don't exist).
// is first value
if (empty($alt)) {
$alt[] = $previous['value'];
}
/*
select * from table_name
where // where starts here
field1 = 'value1' // comes from normal where
or ( // where1 starts here
field1 = 'default'
and NOT EXISTS ( // where2 starts here
select 1 from table_name where field1 = 'value1'
)
/*
select * from table_name
where // where starts here
field1 = 'value1' // comes from normal where
or ( // where1 starts here
field1 = 'default'
and NOT EXISTS ( // where2 starts here
select 1 from table_name where field1 = 'value1'
)
*/
$where1 = new Where($this->db);
$where1->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], 'and');
)
*/
$where1 = new Where($this->db);
$where1->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], 'and');
$where2 = new Builder($this->db);
$where2->select('1')
->from($this->mapper::TABLE . '_d' . $this->depth)
->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, 'in', $alt);
$where2 = new Builder($this->db);
$where2->select('1')
->from($this->mapper::TABLE . '_d' . $this->depth)
->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, 'in', $alt);
$where1->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, 'not exists', $where2, 'and');
$where1->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, 'not exists', $where2, 'and');
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where1, 'or');
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where1, 'or');
$alt[] = $where['value'];
} else {
$previous = $where;
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']);
}
$alt[] = $where['value'];
} else {
$previous = $where;
$query->where($this->mapper::TABLE . '_d' . $this->depth . '.' . $col, $comparison, $where['value'], $where['comparison']);
}
}
}
@ -529,20 +571,15 @@ final class ReadMapper extends DataMapperAbstract
$member = $path[0];
$refProp = $refClass->getProperty($path[0]);
if (!($isPublic = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
$isPublic = $refProp->isPublic();
$aValue = $isPublic ? $obj->{$path[0]} : $refProp->getValue($obj);
\array_shift($path);
$arrayPath = \implode('/', $path);
$aValue = $isPublic ? $obj->{$path[0]} : $refProp->getValue($obj);
} else {
$refProp = $refClass->getProperty($def['internal']);
$member = $def['internal'];
if (!($isPublic = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
$refProp = $refClass->getProperty($def['internal']);
$isPublic = $refProp->isPublic();
$member = $def['internal'];
}
if (isset($this->mapper::OWNS_ONE[$def['internal']])) {
@ -621,10 +658,6 @@ final class ReadMapper extends DataMapperAbstract
$member->unserialize($value);
}
}
if (!$isPublic) {
$refProp->setAccessible(false);
}
}
foreach ($this->mapper::HAS_MANY as $member => $def) {
@ -641,23 +674,17 @@ final class ReadMapper extends DataMapperAbstract
$arrayPath = '/';
if (\stripos($member, '/') !== false) {
$hasPath = true;
$path = \explode('/', $member);
$refProp = $refClass->getProperty($path[0]);
if (!($isPublic = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
$hasPath = true;
$path = \explode('/', $member);
$refProp = $refClass->getProperty($path[0]);
$isPublic = $refProp->isPublic();
\array_shift($path);
$arrayPath = \implode('/', $path);
$aValue = $isPublic ? $obj->{$path[0]} : $refProp->getValue($obj);
} else {
$refProp = $refClass->getProperty($member);
if (!($isPublic = $refProp->isPublic())) {
$refProp->setAccessible(true);
}
$isPublic = $refProp->isPublic();
}
if (\in_array($def['mapper']::COLUMNS[$column]['type'], ['string', 'int', 'float', 'bool'])) {
@ -694,10 +721,6 @@ final class ReadMapper extends DataMapperAbstract
$member = $isPublic ? $obj->{$member} : $refProp->getValue($obj);
$member->unserialize($value);
}
if (!$isPublic) {
$refProp->setAccessible(false);
}
}
return $obj;
@ -874,12 +897,10 @@ final class ReadMapper extends DataMapperAbstract
$refProp = $refClass->getProperty($member);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$refProp->setValue($obj, !\is_array($objects) && ($many['conditional'] ?? false) === false
? [$many['mapper']::getObjectId($objects) => $objects]
: $objects // if conditional === true the obj will be asigned (e.g. has many localizations but only one is loaded for the model)
);
$refProp->setAccessible(false);
} else {
$obj->{$member} = !\is_array($objects) && ($many['conditional'] ?? false) === false
? [$many['mapper']::getObjectId($objects) => $objects]
@ -907,9 +928,7 @@ final class ReadMapper extends DataMapperAbstract
$refProp = $refClass->getProperty($member);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$relMapper->loadHasManyRelations($refProp->getValue($obj));
$refProp->setAccessible(false);
} else {
$relMapper->loadHasManyRelations($obj->{$member});
}

View File

@ -74,7 +74,7 @@ final class UpdateMapper extends DataMapperAbstract
public function executeUpdate(object $obj) : mixed
{
$refClass = new \ReflectionClass($obj);
$objId = $this->mapper::getObjectId($obj, $refClass);
$objId = $this->mapper::getObjectId($obj);
if ($this->mapper::isNullModel($obj)) {
return $objId === 0 ? null : $objId;
@ -128,9 +128,7 @@ final class UpdateMapper extends DataMapperAbstract
$property = $refClass->getProperty($propertyName);
if (!($property->isPublic())) {
$property->setAccessible(true);
$tValue = $property->getValue($obj);
$property->setAccessible(false);
} else {
$tValue = $obj->{$propertyName};
}
@ -244,9 +242,7 @@ final class UpdateMapper extends DataMapperAbstract
$property = $refClass->getProperty($propertyName);
if (!($isPublic = $property->isPublic())) {
$property->setAccessible(true);
$values = $property->getValue($obj);
$property->setAccessible(false);
} else {
$values = $obj->{$propertyName};
}
@ -268,7 +264,7 @@ final class UpdateMapper extends DataMapperAbstract
continue;
}
$primaryKey = $mapper::getObjectId($value, $relReflectionClass);
$primaryKey = $mapper::getObjectId($value);
// already in db
if (!empty($primaryKey)) {
@ -290,9 +286,7 @@ final class UpdateMapper extends DataMapperAbstract
$relProperty = $relReflectionClass->getProperty($mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal']);
if (!$isPublic) {
$relProperty->setAccessible(true);
$relProperty->setValue($value, $objId);
$relProperty->setAccessible(false);
} else {
$value->{$mapper::COLUMNS[$this->mapper::HAS_MANY[$propertyName]['self']]['internal']} = $objId;
}

View File

@ -77,12 +77,12 @@ final class WriteMapper extends DataMapperAbstract
$refClass = new \ReflectionClass($obj);
if ($this->mapper::isNullModel($obj)) {
$objId = $this->mapper::getObjectId($obj, $refClass);
$objId = $this->mapper::getObjectId($obj);
return $objId === 0 ? null : $objId;
}
if (!empty($id = $this->mapper::getObjectId($obj, $refClass)) && $this->mapper::AUTOINCREMENT) {
if (!empty($id = $this->mapper::getObjectId($obj)) && $this->mapper::AUTOINCREMENT) {
$objId = $id;
} else {
$objId = $this->createModel($obj, $refClass);
@ -163,7 +163,7 @@ final class WriteMapper extends DataMapperAbstract
$sth = $this->db->con->prepare($a = $query->toSql());
$sth->execute();
$objId = empty($id = $this->mapper::getObjectId($obj, $refClass)) ? $this->db->con->lastInsertId() : $id;
$objId = empty($id = $this->mapper::getObjectId($obj)) ? $this->db->con->lastInsertId() : $id;
\settype($objId, $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['type']);
return $objId;
@ -231,9 +231,7 @@ final class WriteMapper extends DataMapperAbstract
$refProp = $refClass->getProperty($this->mapper::BELONGS_TO[$propertyName]['by']);
if (!$refProp->isPublic()) {
$refProp->setAccessible(true);
$obj = $refProp->getValue($obj);
$refProp->setAccessible(false);
} else {
$obj = $obj->{$this->mapper::BELONGS_TO[$propertyName]['by']};
}
@ -267,7 +265,6 @@ final class WriteMapper extends DataMapperAbstract
$property = $refClass->getProperty($propertyName);
if (!($isPublic = $property->isPublic())) {
$property->setAccessible(true);
$values = $property->getValue($obj);
} else {
$values = $obj->{$propertyName};
@ -294,25 +291,13 @@ final class WriteMapper extends DataMapperAbstract
$values->{$internalName} = $objId;
}
if (!$isPublic) {
$property->setAccessible(false);
}
$mapper::create(db: $this->db)->execute($values);
continue;
} elseif (!\is_array($values)) {
if (!$isPublic) {
$property->setAccessible(false);
}
// @todo: conditionals???
continue;
}
if (!$isPublic) {
$property->setAccessible(false);
}
$objsIds = [];
$relReflectionClass = !empty($values) ? new \ReflectionClass(\reset($values)) : null;
@ -325,7 +310,7 @@ final class WriteMapper extends DataMapperAbstract
}
/** @var \ReflectionClass $relReflectionClass */
$primaryKey = $mapper::getObjectId($value, $relReflectionClass);
$primaryKey = $mapper::getObjectId($value);
// already in db
if (!empty($primaryKey)) {
@ -337,10 +322,7 @@ final class WriteMapper extends DataMapperAbstract
// Setting relation value (id) for relation (since the relation is not stored in an extra relation table)
if (!isset($this->mapper::HAS_MANY[$propertyName]['external'])) {
$relProperty = $relReflectionClass->getProperty($internalName);
if (!($isRelPublic = $relProperty->isPublic())) {
$relProperty->setAccessible(true);
}
$isRelPublic = $relProperty->isPublic();
// todo maybe consider to just set the column type to object, and then check for that (might be faster)
if (isset($mapper::BELONGS_TO[$internalName])

View File

@ -378,6 +378,10 @@ class Builder extends BuilderAbstract
$dependencies[$table] = [];
foreach ($this->ons[$table] as $on) {
if (!\is_string($on)) {
continue;
}
if (\stripos($on['column'], '.')) {
$dependencies[$table][] = \explode('.', $on['column'])[0];
}
@ -1294,7 +1298,7 @@ class Builder extends BuilderAbstract
*
* @since 1.0.0
*/
public function on(string | array $columns, string | array $operator = null, string | array $values = null, string | array $boolean = 'and', string $table = null) : self
public function on(string | array $columns, string | array $operator = null, mixed $values = null, string | array $boolean = 'and', string $table = null) : self
{
if (!\is_array($columns)) {
$columns = [$columns];

View File

@ -452,6 +452,7 @@ class Grammar extends GrammarAbstract
$expression .= '(' . \rtrim($this->compileWhereQuery($element['column']), ';') . ')';
}
// @todo: on doesn't allow values as value (only table column names). This is bad and needs to be fixed!
if (isset($element['value'])) {
$expression .= ' ' . \strtoupper($element['operator']) . ' ' . $this->compileSystem($element['value']);
} else {

View File

@ -33,7 +33,7 @@ class BaseStringL11n implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Name.
@ -63,7 +63,7 @@ class BaseStringL11n implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $language = ISO639x1Enum::_EN;
public string $language = ISO639x1Enum::_EN;
/**
* Country.
@ -71,7 +71,7 @@ class BaseStringL11n implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $country = ISO3166TwoEnum::_USA;
public string $country = ISO3166TwoEnum::_USA;
/**
* Content.

View File

@ -30,7 +30,7 @@ class BaseStringL11nType implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Identifier for the l11n type.

View File

@ -30,7 +30,7 @@ class City
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Country code.

View File

@ -30,7 +30,7 @@ class Country
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Country name.

View File

@ -30,7 +30,7 @@ class Currency
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Currency name.

View File

@ -30,7 +30,7 @@ class Iban
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Iban country.

View File

@ -30,7 +30,7 @@ class Language
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Language name.

View File

@ -26,12 +26,18 @@ use phpOMS\Stdlib\Base\Enum;
*/
class ISO4217CharEnum extends Enum
{
public const _AED = 'AED';
public const _ALL = 'ALL';
public const _AMD = 'AMD';
public const _AFN = 'AFN';
public const _ARS = 'ARS';
public const _AOA = 'AOA';
public const _AWG = 'AWG';
public const _AUD = 'AUD';
@ -90,8 +96,6 @@ class ISO4217CharEnum extends Enum
public const _SVC = 'SVC';
public const _EEK = 'EEK';
public const _EUR = 'EUR';
public const _FKP = 'FKP';
@ -253,4 +257,150 @@ class ISO4217CharEnum extends Enum
public const _YER = 'YER';
public const _ZWD = 'ZWD';
public const _ZMK = 'ZMK';
public const _ZWL = 'ZWL';
public const _BDT = 'BDT';
public const _BHD = 'BHD';
public const _BIF = 'BIF';
public const _BOV = 'BOV';
public const _BTN = 'BTN';
public const _CDF = 'CDF';
public const _CHE = 'CHE';
public const _CHW = 'CHW';
public const _CLF = 'CLF';
public const _COU = 'COU';
public const _CUC = 'CUC';
public const _CVE = 'CVE';
public const _DJF = 'DJF';
public const _DZD = 'DZD';
public const _ERN = 'ERN';
public const _ETB = 'ETB';
public const _GEL = 'GEL';
public const _GHS = 'GHS';
public const _GMD = 'GMD';
public const _GNF = 'GNF';
public const _HTG = 'HTG';
public const _IQD = 'IQD';
public const _JOD = 'JOD';
public const _KMF = 'KMF';
public const _KWD = 'KWD';
public const _LSL = 'LSL';
public const _LYD = 'LYD';
public const _MAD = 'MAD';
public const _MDL = 'MDL';
public const _MGA = 'MGA';
public const _MMK = 'MMK';
public const _MOP = 'MOP';
public const _MRO = 'MRO';
public const _MVR = 'MVR';
public const _MWK = 'MWK';
public const _MXV = 'MXV';
public const _PGK = 'PGK';
public const _RWF = 'RWF';
public const _SDG = 'SDG';
public const _SLL = 'SLL';
public const _SSP = 'SSP';
public const _STD = 'STD';
public const _SZL = 'SZL';
public const _TJS = 'TJS';
public const _TMT = 'TMT';
public const _TND = 'TND';
public const _TOP = 'TOP';
public const _TZS = 'TZS';
public const _UGX = 'UGX';
public const _USN = 'USN';
public const _USS = 'USS';
public const _UYI = 'UYI';
public const _VUV = 'VUV';
public const _WST = 'WST';
public const _XAF = 'XAF';
public const _XAG = 'XAG';
public const _XAU = 'XAU';
public const _XBA = 'XBA';
public const _XBB = 'XBB';
public const _XBC = 'XBC';
public const _XBD = 'XBD';
public const _XDR = 'XDR';
public const _XFU = 'XFU';
public const _XOF = 'XOF';
public const _XPD = 'XPD';
public const _XPF = 'XPF';
public const _XPT = 'XPT';
public const _XSU = 'XSU';
public const _XTS = 'XTS';
public const _XUA = 'XUA';
public const _ZMW = 'ZMW';
}

View File

@ -381,4 +381,28 @@ class ISO4217DecimalEnum extends Enum
public const _ZAR = 2;
public const _ZMW = 2;
public const _GGP = 2;
public const _GHC = 2;
public const _IMP = 2;
public const _JEP = 2;
public const _LTL = 2;
public const _LVL = 2;
public const _SVC = 2;
public const _TRL = 2;
public const _TVD = 2;
public const _ZWD = 2;
public const _ZMK = 2;
public const _ZWL = 2;
}

View File

@ -26,8 +26,12 @@ use phpOMS\Stdlib\Base\Enum;
*/
class ISO4217Enum extends Enum
{
public const _AED = 'United Arab Emirates, Dirham';
public const _ALL = 'Albania, Leke';
public const _AMD = 'Armenian, Dram';
public const _AFN = 'Afghanistan, Afghanis';
public const _ARS = 'Argentina, Pesos';
@ -38,6 +42,8 @@ class ISO4217Enum extends Enum
public const _AZN = 'Azerbaijan, New Manats';
public const _AOA = 'Angolan, Kwanza';
public const _BSD = 'Bahamas, Dollars';
public const _BBD = 'Barbados, Dollars';
@ -90,8 +96,6 @@ class ISO4217Enum extends Enum
public const _SVC = 'El Salvador, Colones';
public const _EEK = 'Estonia, Krooni';
public const _EUR = 'Euro';
public const _FKP = 'Falkland Islands, Pounds';
@ -253,4 +257,150 @@ class ISO4217Enum extends Enum
public const _YER = 'Yemen, Rials';
public const _ZWD = 'Zimbabwe, Zimbabwe Dollars';
public const _ZMK = 'Zambian, Kwacha';
public const _ZWL = 'Zimbabwean, Dollar';
public const _BDT = 'Bangladeshi, Taka';
public const _BHD = 'Bahraini, Dinar';
public const _BIF = 'Burundian, Franc';
public const _BOV = 'Bolivian, Mvdol';
public const _BTN = 'Bhutanes,e Ngultrum';
public const _CDF = 'Congolese, Franc';
public const _CHE = 'WIR Euro (complementary currency)';
public const _CHW = 'WIR Franc (complementary currency)';
public const _CLF = 'Unidad de Fomento (funds code)';
public const _COU = 'Unidad de Valor Real (UVR) (funds code)';
public const _CUC = 'Cuban convertible, Peso';
public const _CVE = 'Cape Verdean, Escudo';
public const _DJF = 'Djiboutian, Franc';
public const _DZD = 'Algerian, Dinar';
public const _ERN = 'Eritrean, Nakfa';
public const _ETB = 'Ethiopian, Birr';
public const _GEL = 'Georgian, Lari';
public const _GHS = 'Ghanaian, Cedi';
public const _GMD = 'Gambian, Dalasi';
public const _GNF = 'Guinean, Franc';
public const _HTG = 'Haitian, Gourde';
public const _IQD = 'Iraqi, Dinar';
public const _JOD = 'Jordanian, Dinar';
public const _KMF = 'Comorian, Franc';
public const _KWD = 'Kuwaiti, Dinar';
public const _LSL = 'Lesotho, Loti';
public const _LYD = 'Libyan, Dinar';
public const _MAD = 'Moroccan, Dirham';
public const _MDL = 'Moldovan, Leu';
public const _MGA = 'Malagasy, Ariary';
public const _MMK = 'Burmese, Kyat';
public const _MOP = 'Macanese, Pataca';
public const _MRO = 'Mauritanian, Ouguiya';
public const _MVR = 'Maldivian, Rufiyaa';
public const _MWK = 'Malawian, Kwacha';
public const _MXV = 'Mexican, Investment Unit';
public const _PGK = 'Papua New Guinean, Kina';
public const _RWF = 'Rwandan, Franc';
public const _SDG = 'Sudanese, Pound';
public const _SLL = 'Sierra Leonean, Leone';
public const _SSP = 'South Sudanese, Pound';
public const _STD = 'São Tomé and Príncipe, Dobra';
public const _SZL = 'Swazi, Lilangeni';
public const _TJS = 'Tajikistani, Somoni';
public const _TMT = 'Turkmenistani, Manat';
public const _TND = 'Tunisian, Dinar';
public const _TOP = 'Tongan, Paʻanga';
public const _TZS = 'Tanzanian, Shilling';
public const _UGX = 'Ugandan, Shilling';
public const _USN = 'United States dollar (next day) (funds code)';
public const _USS = 'United States dollar (same day) (funds code)';
public const _UYI = 'Uruguay Peso en Unidades Indexadas (URUIURUI) (funds code)';
public const _VUV = 'Vanuatu, Vatu';
public const _WST = 'Samoan, Tala';
public const _XAF = 'Central African, CFA Franc';
public const _XAG = 'Silver (one troy ounce)';
public const _XAU = 'Gold (one troy ounce)';
public const _XBA = 'European, Composite Unit (EURCO) (bond market unit)';
public const _XBB = 'European, Monetary Unit (E.M.U.-6) (bond market unit)';
public const _XBC = 'European, Unit of Account 9 (E.U.A.-9) (bond market unit)';
public const _XBD = 'European, Unit of Account 17 (E.U.A.-17) (bond market unit)';
public const _XDR = 'Special drawing rights';
public const _XFU = 'UIC franc (special settlement currency)';
public const _XOF = 'West African, CFA franc';
public const _XPD = 'Palladium';
public const _XPF = 'CFP franc';
public const _XPT = 'Platinum';
public const _XSU = 'Sucre';
public const _XTS = 'Testing Currency Code';
public const _XUA = 'ADB Unit of Account';
public const _ZMW = 'Zambian, kwacha';
}

View File

@ -381,4 +381,16 @@ class ISO4217NumEnum extends Enum
public const _ZAR = '710';
public const _ZMW = '967';
public const _GHC = '936';
public const _LTL = '440';
public const _LVL = '428';
public const _TRL = '949';
public const _ZMK = '894';
public const _ZWL = '932';
}

View File

@ -40,6 +40,8 @@ class ISO4217SubUnitEnum extends Enum
public const _AUD = 100;
public const _AOA = 100;
public const _AWG = 100;
public const _BAM = 100;
@ -102,6 +104,8 @@ class ISO4217SubUnitEnum extends Enum
public const _EGP = 100;
public const _GGP = 100;
public const _ERN = 100;
public const _EUR = 100;
@ -333,4 +337,70 @@ class ISO4217SubUnitEnum extends Enum
public const _ZMK = 100;
public const _ZWL = 100;
public const _GHC = 100;
public const _IMP = 100;
public const _JEP = 100;
public const _TRL = 100;
public const _TVD = 100;
public const _ZWD = 100;
public const _BOV = 100;
public const _CHE = 100;
public const _CHW = 100;
public const _CLF = 10000;
public const _COU = 100;
public const _ETB = 100;
public const _MXV = 100;
public const _USN = 100;
public const _USS = 100;
public const _UYI = 0;
public const _XAG = 0;
public const _XAU = 0;
public const _XBA = 0;
public const _XBB = 0;
public const _XBC = 0;
public const _XBD = 0;
public const _XDR = 0;
public const _XFU = 0;
public const _XPD = 0;
public const _XPT = 0;
public const _XSU = 0;
public const _XTS = 0;
public const _XUA = 0;
public const _ZMW = 100;
public const _AZN = 100;
public const _CRC = 100;
public const _GIP = 100;
}

View File

@ -26,8 +26,12 @@ use phpOMS\Stdlib\Base\Enum;
*/
class ISO4217SymbolEnum extends Enum
{
public const _AED = 'د.إ';
public const _ALL = 'Lek';
public const _AMD = '֏';
public const _AFN = '؋';
public const _ARS = '$';
@ -38,6 +42,8 @@ class ISO4217SymbolEnum extends Enum
public const _AZN = 'ман';
public const _AOA = 'Kz';
public const _BSD = '$';
public const _BBD = '$';
@ -243,4 +249,156 @@ class ISO4217SymbolEnum extends Enum
public const _YER = '﷼';
public const _ZWD = 'Z$';
public const _GHC = '₵';
public const _LTL = 'LTL';
public const _LVL = 'LVL';
public const _TRL = 'TRY';
public const _ZMK = 'ZK';
public const _ZWL = 'Z';
public const _BDT = '৳';
public const _BHD = 'BHD';
public const _BIF = 'BIF';
public const _BOV = 'BOV';
public const _BTN = '₹';
public const _CDF = 'CDF';
public const _CHE = 'CHF';
public const _CHW = 'CHF';
public const _CLF = 'CLF';
public const _COU = 'COU';
public const _CUC = '$;';
public const _CVE = '$;';
public const _DJF = 'DJF';
public const _DZD = 'DZD';
public const _ERN = 'ERN';
public const _ETB = 'ETB';
public const _GEL = '₾';
public const _GNF = 'GNF';
public const _HTG = 'HTG';
public const _IQD = 'IQD';
public const _JOD = 'JOD';
public const _KMF = 'KMF';
public const _KWD = 'KWD';
public const _LSL = 'LSL';
public const _LYD = 'LYD';
public const _MAD = 'MAD';
public const _MDL = 'MDL';
public const _MGA = 'MGA';
public const _MMK = 'MMK';
public const _MOP = 'MOP';
public const _MRO = 'MRO';
public const _MVR = 'MVR';
public const _MWK = 'MWK';
public const _MXV = 'MXV';
public const _PGK = 'PGK';
public const _RWF = 'RWF';
public const _SDG = '£';
public const _SLL = 'SLL';
public const _SSP = '£';
public const _STD = 'STD';
public const _SZL = 'SZL';
public const _TJS = 'TJS';
public const _TMT = 'TMT';
public const _TND = 'TND';
public const _TOP = 'T';
public const _TZS = 'TZS';
public const _UGX = 'UGX';
public const _USN = 'USN';
public const _USS = 'USS';
public const _UYI = 'UYI';
public const _VUV = 'VUV';
public const _WST = 'WST';
public const _XAF = 'XAF';
public const _XAG = 'XAG';
public const _XAU = 'XAU';
public const _XBA = 'XBA';
public const _XBB = 'XBB';
public const _XBC = 'XBC';
public const _XBD = 'XBD';
public const _XDR = 'XDR';
public const _XFU = 'XFU';
public const _XOF = 'XOF';
public const _XPD = 'XPD';
public const _XPF = 'XPF';
public const _XPT = 'XPT';
public const _XSU = 'XSU';
public const _XTS = 'XTS';
public const _XUA = 'XUA';
public const _ZMW = 'ZK';
public const _KES = 'KSh';
}

View File

@ -186,6 +186,8 @@ class ISO639x1Enum extends Enum
public const _KR = 'kr';
public const _KS = 'ks';
public const _KK = 'kk';
public const _KM = 'km';
@ -216,6 +218,8 @@ class ISO639x1Enum extends Enum
public const _LT = 'lt';
public const _LU = 'lu';
public const _LV = 'lv';
public const _GV = 'gv';
@ -294,6 +298,8 @@ class ISO639x1Enum extends Enum
public const _SC = 'sc';
public const _SD = 'sd';
public const _SE = 'se';
public const _SM = 'sm';
@ -350,10 +356,14 @@ class ISO639x1Enum extends Enum
public const _TS = 'ts';
public const _TT = 'tt';
public const _TW = 'tw';
public const _TY = 'ty';
public const _UG = 'ug';
public const _UK = 'uk';
public const _UR = 'ur';

View File

@ -269,7 +269,7 @@ final class L11nManager
*/
public function getCurrency(
Localization $l11n,
int | float | Money $currency,
int | float | Money | FloatInt $currency,
string $symbol = null,
string $format = null,
int $divide = 1
@ -292,6 +292,10 @@ final class L11nManager
}
}
if ($currency instanceof FloatInt) {
$currency = $currency->value;
}
$money = !($currency instanceof Money)
? new Money((int) ($currency / $divide))
: $currency;

View File

@ -42,7 +42,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $country = ISO3166TwoEnum::_XXX;
public string $country = ISO3166TwoEnum::_XXX;
/**
* Timezone.
@ -50,7 +50,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $timezone = 'America/New_York';
public string $timezone = 'America/New_York';
/**
* Language ISO code.
@ -58,7 +58,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $language = ISO639x1Enum::_EN;
public string $language = ISO639x1Enum::_EN;
/**
* Currency.
@ -66,7 +66,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $currency = ISO4217CharEnum::_USD;
public string $currency = ISO4217CharEnum::_USD;
/**
* Currency format.
@ -74,7 +74,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $currencyFormat = '0';
public string $currencyFormat = '0';
/**
* Number format.
@ -82,7 +82,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $decimal = '.';
public string $decimal = '.';
/**
* Number format.
@ -90,7 +90,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $thousands = ',';
public string $thousands = ',';
/**
* Angle type.
@ -98,7 +98,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $angle = AngleType::DEGREE;
public string $angle = AngleType::DEGREE;
/**
* Temperature type.
@ -106,7 +106,7 @@ class Localization implements \JsonSerializable
* @var string
* @since 1.0.0
*/
protected string $temperature = TemperatureType::CELSIUS;
public string $temperature = TemperatureType::CELSIUS;
/**
* Precision.
@ -114,7 +114,7 @@ class Localization implements \JsonSerializable
* @var array<string, int>
* @since 1.0.0
*/
protected array $precision = [];
public array $precision = [];
/**
* Time format.
@ -122,7 +122,7 @@ class Localization implements \JsonSerializable
* @var array<string, string>
* @since 1.0.0
*/
protected array $datetime = [];
public array $datetime = [];
/**
* Weight.
@ -130,7 +130,7 @@ class Localization implements \JsonSerializable
* @var array<string, string>
* @since 1.0.0
*/
protected array $weight = [];
public array $weight = [];
/**
* Speed.
@ -138,7 +138,7 @@ class Localization implements \JsonSerializable
* @var array<string, string>
* @since 1.0.0
*/
protected array $speed = [];
public array $speed = [];
/**
* Length.
@ -146,7 +146,7 @@ class Localization implements \JsonSerializable
* @var array<string, string>
* @since 1.0.0
*/
protected array $length = [];
public array $length = [];
/**
* Area.
@ -154,7 +154,7 @@ class Localization implements \JsonSerializable
* @var array<string, string>
* @since 1.0.0
*/
protected array $area = [];
public array $area = [];
/**
* Volume.
@ -162,7 +162,7 @@ class Localization implements \JsonSerializable
* @var array<string, string>
* @since 1.0.0
*/
protected array $volume = [];
public array $volume = [];
/**
* Country id.
@ -170,7 +170,7 @@ class Localization implements \JsonSerializable
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Get id
@ -273,7 +273,21 @@ class Localization implements \JsonSerializable
return;
}
$this->importLocale($json);
$this->language = $json['language'] ?? 'en';
$this->country = $json['country'] ?? 'US';
$this->currency = $json['currency']['code'] ?? ISO4217Enum::_USD;
$this->thousands = $json['thousand'] ?? ',';
$this->decimal = $json['decimal'] ?? '.';
$this->angle = $json['angle'] ?? AngleType::DEGREE;
$this->temperature = $json['temperature'] ?? TemperatureType::CELSIUS;
$this->weight = $json['weight'] ?? [];
$this->speed = $json['speed'] ?? [];
$this->length = $json['length'] ?? [];
$this->area = $json['area'] ?? [];
$this->volume = $json['volume'] ?? [];
$this->precision = $json['precision'] ?? [];
$this->timezone = $json['timezone'] ?? 'America/New_York';
$this->datetime = $json['datetime'] ?? [];
return;
}
@ -288,7 +302,21 @@ class Localization implements \JsonSerializable
return;
}
$this->importLocale($json);
$this->language = $json['language'] ?? 'en';
$this->country = $json['country'] ?? 'US';
$this->currency = $json['currency']['code'] ?? ISO4217Enum::_USD;
$this->thousands = $json['thousand'] ?? ',';
$this->decimal = $json['decimal'] ?? '.';
$this->angle = $json['angle'] ?? AngleType::DEGREE;
$this->temperature = $json['temperature'] ?? TemperatureType::CELSIUS;
$this->weight = $json['weight'] ?? [];
$this->speed = $json['speed'] ?? [];
$this->length = $json['length'] ?? [];
$this->area = $json['area'] ?? [];
$this->volume = $json['volume'] ?? [];
$this->precision = $json['precision'] ?? [];
$this->timezone = $json['timezone'] ?? 'America/New_York';
$this->datetime = $json['datetime'] ?? [];
}
/**

View File

@ -90,4 +90,12 @@ final class Money extends FloatInt
{
return $this->symbol;
}
public static function fromFloatInt(FloatInt $value) : self
{
$money = new self();
$money->value = $value->value;
return $money;
}
}

View File

@ -62,18 +62,23 @@ final class HttpHeader extends HeaderAbstract
return false;
}
$key = \strtolower($key);
if (self::isSecurityHeader($key) && isset($this->header[$key])) {
$key = \strtolower($key);
$exists = isset($this->header[$key]);
if (!$overwrite && $exists) {
return false;
}
if (!$overwrite && isset($this->header[$key])) {
if ($exists && self::isSecurityHeader($key)) {
return false;
}
unset($this->header[$key]);
if ($exists && $overwrite) {
unset($this->header[$key]);
$exists = false;
}
if (!isset($this->header[$key])) {
if (!$exists) {
$this->header[$key] = [];
}

View File

@ -368,22 +368,11 @@ final class HttpRequest extends RequestAbstract
*
* @since 1.0.0
*/
public function getRequestLanguage() : string
private function getRequestLanguage() : string
{
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return 'en';
}
// @codeCoverageIgnoreStart
$components = \explode(';', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$locals = \stripos($components[0], ',') !== false
? $locals = \explode(',', $components[0])
: $components;
$firstLocalComponents = \explode('-', $locals[0]);
// @codeCoverageIgnoreEnd
$language = \strtolower($firstLocalComponents[0]);
$locale = $this->getLocale();
$firstLocalComponents = \explode('_', $locale);
$language = \strtolower($firstLocalComponents[0]);
return ISO639x1Enum::isValidValue($language) ? $language : 'en';
}
@ -395,22 +384,11 @@ final class HttpRequest extends RequestAbstract
*
* @since 1.0.0
*/
public function getRequestCountry() : string
private function getRequestCountry() : string
{
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return '';
}
// @codeCoverageIgnoreStart
$components = \explode(';', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$locals = \stripos($components[0], ',') !== false
? $locals = \explode(',', $components[0])
: $components;
$firstLocalComponents = \explode('-', $locals[0]);
// @codeCoverageIgnoreEnd
$country = \strtoupper($firstLocalComponents[1] ?? '');
$locale = $this->getLocale();
$firstLocalComponents = \explode('_', $locale);
$country = \strtoupper($firstLocalComponents[1] ?? '');
return ISO3166TwoEnum::isValidValue($country) ? $country : 'US';
}
@ -424,6 +402,10 @@ final class HttpRequest extends RequestAbstract
*/
public function getLocale() : string
{
if (!empty($this->locale)) {
return $this->locale = $this->header->l11n->getLanguage() . '_' . $this->header->l11n->getCountry();
}
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return 'en_US';
}
@ -435,7 +417,9 @@ final class HttpRequest extends RequestAbstract
: $components;
// @codeCoverageIgnoreEnd
return \str_replace('-', '_', $locals[0]); // @codeCoverageIgnore
$this->locale = \str_replace('-', '_', $locals[0]); // @codeCoverageIgnore
return $this->locale;
}
/**

View File

@ -170,7 +170,7 @@ class MailHandler
* @var string
* @since 1.0.0
*/
public string $dsn = DsnNotificationType::NONE;
public string $dsn = DsnNotificationLevel:NONE;
/**
* Keep connection alive.

View File

@ -609,7 +609,7 @@ class Smtp
*
* @since 1.0.0
*/
public function recipient(string $address, string $dsn = DsnNotificationType::NONE) : bool
public function recipient(string $address, string $dsn = DsnNotificationLevel:NONE) : bool
{
if ($dsn === '') {
$rcpt = 'RCPT TO:<' . $address . '>';

View File

@ -66,6 +66,14 @@ abstract class RequestAbstract implements MessageInterface
*/
public HeaderAbstract $header;
/**
* Local
*
* @var string
* @since 1.0.0
*/
protected string $locale = '';
/**
* Request hash.
*
@ -141,7 +149,11 @@ abstract class RequestAbstract implements MessageInterface
{
$key = \mb_strtolower($key);
return isset($this->data[$key]) ? (string) $this->data[$key] : null;
if (($this->data[$key] ?? '') === '') {
return null;
}
return (string) $this->data[$key];
}
/**
@ -157,7 +169,11 @@ abstract class RequestAbstract implements MessageInterface
{
$key = \mb_strtolower($key);
return isset($this->data[$key]) ? (int) $this->data[$key] : null;
if (($this->data[$key] ?? '') === '') {
return null;
}
return (int) $this->data[$key];
}
/**
@ -173,7 +189,11 @@ abstract class RequestAbstract implements MessageInterface
{
$key = \mb_strtolower($key);
return isset($this->data[$key]) ? (float) $this->data[$key] : null;
if (($this->data[$key] ?? '') === '') {
return null;
}
return (float) $this->data[$key];
}
/**
@ -189,7 +209,11 @@ abstract class RequestAbstract implements MessageInterface
{
$key = \mb_strtolower($key);
return isset($this->data[$key]) ? (bool) $this->data[$key] : null;
if (($this->data[$key] ?? '') === '') {
return null;
}
return (bool) $this->data[$key];
}
/**
@ -221,7 +245,7 @@ abstract class RequestAbstract implements MessageInterface
{
$key = \mb_strtolower($key);
if (!isset($this->data[$key])) {
if (($this->data[$key] ?? '') === '') {
return [];
}
@ -244,7 +268,7 @@ abstract class RequestAbstract implements MessageInterface
{
$key = \mb_strtolower($key);
if (!isset($this->data[$key])) {
if (($this->data[$key] ?? '') === '') {
return [];
}

View File

@ -1,42 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package phpOMS\Model\Message
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\Model\Message;
use phpOMS\Stdlib\Base\Enum;
/**
* NotifyType class.
*
* @package phpOMS\Model\Message
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
abstract class NotifyType extends Enum
{
public const BINARY = 'binary';
public const OK = 'ok';
public const INFO = 'info';
public const WARNING = 'warning';
public const ERROR = 'error';
public const FATAL = 'fatal';
public const HIDDEN = 'hidden';
}

View File

@ -137,7 +137,7 @@ final class SocketRouter implements RouterInterface
// if permission check is invalid
if (isset($d['permission']) && !empty($d['permission'])
&& ($account === null || $account instanceof NullAccount)
&& ($account === null || $account->getId() === 0)
) {
return ['dest' => RouteStatus::NOT_LOGGED_IN];
} elseif (isset($d['permission']) && !empty($d['permission'])

View File

@ -139,7 +139,7 @@ final class WebRouter implements RouterInterface
// if permission check is invalid
if (isset($d['permission']) && !empty($d['permission'])
&& ($account === null || $account instanceof NullAccount)
&& ($account === null || $account->getId() === 0)
) {
return ['dest' => RouteStatus::NOT_LOGGED_IN];
} elseif (isset($d['permission']) && !empty($d['permission'])

View File

@ -68,6 +68,45 @@ final class EncryptionHelper
return $result;
}
public static function encryptFile(string $in, string $out, string $keyHex) : bool
{
$fpSource = \fopen($in, 'r+');
$fpEncoded = \fopen($out . '.tmp', 'w');
if ($fpSource === false || $fpEncoded === false) {
return false;
}
$secretKey = \sodium_hex2bin($keyHex);
$nonce = \random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
while (($buffer = \fgets($fpSource, 4096)) !== false) {
$ciphertext = \sodium_crypto_secretbox($buffer, $nonce, $keyHex);
\fwrite($fpEncoded, $ciphertext);
}
\fclose($fpSource);
\fclose($fpEncoded);
if ($in === $out) {
\unlink($in);
}
\rename($out . '.tmp', $out);
\sodium_memzero($nonce);
\sodium_memzero($secretKey);
\sodium_memzero($ciphertext);
/*
\sodium_memzero($message);
\sodium_memzero($keyHex);
*/
return true;
}
/**
* Decrypt an encrypted message
*
@ -80,6 +119,10 @@ final class EncryptionHelper
*/
public static function decryptShared(string $encrypted, string $keyHex) : string
{
if ($encrypted === '' || $keyHex === '') {
return $encrypted;
}
$secretKey = \sodium_hex2bin($keyHex);
$ciphertext = \sodium_base642bin($encrypted, SODIUM_BASE64_VARIANT_ORIGINAL);
@ -99,6 +142,47 @@ final class EncryptionHelper
return $plaintext === false ? '' : $plaintext;
}
public static function decryptFile(string $in, string $out, string $keyHex) : bool
{
$fpSource = \fopen($in, 'r+');
$fpDecoded = \fopen($out . '.tmp', 'w');
if ($fpSource === false || $fpDecoded === false) {
return false;
}
$secretKey = \sodium_hex2bin($keyHex);
while (($buffer = \fgets($fpSource, 4096)) !== false) {
$ciphertext = \sodium_base642bin($buffer, SODIUM_BASE64_VARIANT_ORIGINAL);
$nonce = \mb_substr($ciphertext, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = \mb_substr($ciphertext, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = \sodium_crypto_secretbox_open($ciphertext, $nonce, $secretKey);
\fwrite($fpDecoded, $plaintext);
}
\fclose($fpSource);
\fclose($fpDecoded);
if ($in === $out) {
\unlink($in);
}
\rename($out . '.tmp', $out);
\sodium_memzero($nonce);
\sodium_memzero($secretKey);
\sodium_memzero($ciphertext);
/*
\sodium_memzero($keyHex);
*/
return true;
}
/**
* Create a paired keys.
*
@ -174,6 +258,10 @@ final class EncryptionHelper
*/
public static function decryptSecret(string $encrypted, string $privateKeyHex, string $publicKeyHex) : string
{
if ($encrypted === '' || $privateKeyHex === '' || $publicKeyHex === '') {
return $encrypted;
}
$privateKey = \sodium_hex2bin($privateKeyHex);
$publicKey = \sodium_hex2bin($publicKeyHex);

View File

@ -39,7 +39,8 @@ abstract class Enum
*/
public static function isValidValue(mixed $value) : bool
{
$constants = self::getConstants();
$reflect = new \ReflectionClass(static::class);
$constants = $reflect->getConstants();
return \in_array($value, $constants, true);
}
@ -67,7 +68,8 @@ abstract class Enum
*/
public static function getRandom() : mixed
{
$constants = self::getConstants();
$reflect = new \ReflectionClass(static::class);
$constants = $reflect->getConstants();
$keys = \array_keys($constants);
return $constants[$keys[\mt_rand(0, \count($constants) - 1)]];
@ -104,9 +106,10 @@ abstract class Enum
*/
public static function getName(string $value) : bool | int | string
{
$arr = self::getConstants();
$reflect = new \ReflectionClass(static::class);
$constants = $reflect->getConstants();
return \array_search($value, $arr);
return \array_search($value, $constants);
}
/**

View File

@ -40,7 +40,7 @@ class FloatInt implements SerializableInterface
* @var string
* @since 1.0.0
*/
protected string $thousands = ',';
public string $thousands = ',';
/**
* Decimal separator.
@ -48,7 +48,7 @@ class FloatInt implements SerializableInterface
* @var string
* @since 1.0.0
*/
protected string $decimal = '.';
public string $decimal = '.';
/**
* Value.
@ -56,7 +56,7 @@ class FloatInt implements SerializableInterface
* @var int
* @since 1.0.0
*/
protected int $value = 0;
public int $value = 0;
/**
* Constructor.

View File

@ -33,7 +33,7 @@ class Location implements \JsonSerializable, SerializableInterface
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $id = 0;
/**
* Zip or postal.

View File

@ -34,6 +34,8 @@ final class UriFactory
*/
private static array $uri = [];
private static ?\Closure $replaceFunction = null;
/**
* Constructor.
*
@ -299,9 +301,8 @@ final class UriFactory
return $uri;
}
$parsed = \preg_replace_callback(
'(\{[\/#\?%@\.\$][a-zA-Z0-9_\-]*\})',
function ($match) use ($toMatch) : string {
if (self::$replaceFunction === null) {
self::$replaceFunction = static function ($match) use ($toMatch) : string {
$match = \substr($match[0], 1, \strlen($match[0]) - 2);
return (string) ($toMatch[$match]
@ -311,7 +312,12 @@ final class UriFactory
: ''
)
));
},
};
}
$parsed = \preg_replace_callback(
'(\{[\/#\?%@\.\$][a-zA-Z0-9_\-]*\})',
self::$replaceFunction,
$uri
);

View File

@ -76,6 +76,10 @@ abstract class SchedulerAbstract
*/
public static function guessBin() : bool
{
if (self::$bin !== '') {
return true;
}
$paths = [
'c:/WINDOWS/system32/schtasks.exe',
'd:/WINDOWS/system32/schtasks.exe',
@ -135,7 +139,7 @@ abstract class SchedulerAbstract
$status = \proc_close($resource);
if ($status === -1) {
if ($status === -1 || $stderr !== '') {
throw new \Exception((string) $stderr);
}
@ -214,7 +218,7 @@ abstract class SchedulerAbstract
/**+
* Reload the jobs
*
*
* @return void
* @since 1.0.0
*/

View File

@ -350,7 +350,7 @@ class View extends ViewAbstract
* @since 1.0.0
*/
public function getCurrency(
int | float | Money $currency,
int | float | Money | FloatInt $currency,
string $symbol = null,
string $format = null,
int $divide = 1

View File

@ -18,7 +18,7 @@ use phpOMS\Contract\SerializableInterface;
class BaseModel
{
protected int $id = 0;
public int $id = 0;
public string $string = 'Base';

View File

@ -155,8 +155,8 @@ final class L11nManagerTest extends \PHPUnit\Framework\TestCase
public function testGetCurrency() : void
{
$l11n = Localization::fromLanguage('en');
self::assertEquals('USD 1.23', $this->l11nManager->getCurrency($l11n, 1.2345, 'medium'));
self::assertEquals('USD 1.235', $this->l11nManager->getCurrency($l11n, 1.2345, 'long'));
self::assertEquals('USD 1.23', $this->l11nManager->getCurrency($l11n, 1.2345, 'USD'));
self::assertEquals('USD 1.235', $this->l11nManager->getCurrency($l11n, 1.2345, 'USD'));
$this->l11nManager->loadLanguage('en', '0', ['0' => ['CurrencyK' => 'K']]);
$this->l11nManager->loadLanguage('en', '0', ['0' => ['CurrencyM' => 'M']]);

View File

@ -41,22 +41,6 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
$this->localization = new Localization();
}
/**
* @testdox The localization has the expected member variables
* @covers phpOMS\Localization\Localization
* @group framework
*/
public function testAttributes() : void
{
self::assertObjectHasAttribute('country', $this->localization);
self::assertObjectHasAttribute('timezone', $this->localization);
self::assertObjectHasAttribute('language', $this->localization);
self::assertObjectHasAttribute('currency', $this->localization);
self::assertObjectHasAttribute('decimal', $this->localization);
self::assertObjectHasAttribute('thousands', $this->localization);
self::assertObjectHasAttribute('datetime', $this->localization);
}
/**
* @testdox The localization has the expected default values after initialization
* @covers phpOMS\Localization\Localization

View File

@ -14,8 +14,8 @@ declare(strict_types=1);
namespace phpOMS\tests\phpOMS\Model\Message;
use phpOMS\Message\NotificationLevel;
use phpOMS\Model\Message\Notify;
use phpOMS\Model\Message\NotifyType;
/**
* @internal
@ -35,7 +35,7 @@ final class NotifyTest extends \PHPUnit\Framework\TestCase
self::assertEquals('', $obj->toArray()['title']);
self::assertEquals('', $obj->toArray()['msg']);
self::assertEquals(0, $obj->toArray()['stay']);
self::assertEquals(NotifyType::INFO, $obj->toArray()['level']);
self::assertEquals(NotificationLevel::INFO, $obj->toArray()['level']);
}
/**
@ -44,10 +44,10 @@ final class NotifyTest extends \PHPUnit\Framework\TestCase
*/
public function testSetGet() : void
{
$obj = new Notify('message', NotifyType::WARNING);
$obj = new Notify('message', NotificationLevel::WARNING);
$obj->delay = 3;
$obj->stay = 5;
$obj->level = NotifyType::ERROR;
$obj->level = NotificationLevel::ERROR;
$obj->message ='msg';
$obj->title = 'title';
@ -57,7 +57,7 @@ final class NotifyTest extends \PHPUnit\Framework\TestCase
'stay' => 5,
'msg' => 'msg',
'title' => 'title',
'level' => NotifyType::ERROR,
'level' => NotificationLevel::ERROR,
], $obj->toArray());
self::assertEquals(\json_encode([
@ -66,7 +66,7 @@ final class NotifyTest extends \PHPUnit\Framework\TestCase
'stay' => 5,
'msg' => 'msg',
'title' => 'title',
'level' => NotifyType::ERROR,
'level' => NotificationLevel::ERROR,
]), $obj->serialize());
self::assertEquals([
@ -75,7 +75,7 @@ final class NotifyTest extends \PHPUnit\Framework\TestCase
'stay' => 5,
'msg' => 'msg',
'title' => 'title',
'level' => NotifyType::ERROR,
'level' => NotificationLevel::ERROR,
], $obj->jsonSerialize());
$obj2 = new Notify();

View File

@ -1,54 +0,0 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\tests\phpOMS\Model\Message;
use phpOMS\Model\Message\NotifyType;
/**
* @internal
*/
final class NotifyTypeTest extends \PHPUnit\Framework\TestCase
{
/**
* @group framework
* @coversNothing
*/
public function testEnumCount() : void
{
self::assertCount(7, NotifyType::getConstants());
}
/**
* @group framework
* @coversNothing
*/
public function testUnique() : void
{
self::assertEquals(NotifyType::getConstants(), \array_unique(NotifyType::getConstants()));
}
/**
* @group framework
* @coversNothing
*/
public function testEnums() : void
{
self::assertEquals('binary', NotifyType::BINARY);
self::assertEquals('info', NotifyType::INFO);
self::assertEquals('warning', NotifyType::WARNING);
self::assertEquals('error', NotifyType::ERROR);
self::assertEquals('fatal', NotifyType::FATAL);
}
}

View File

@ -201,8 +201,8 @@ final class UriFactoryTest extends \PHPUnit\Framework\TestCase
*/
public function testDuplicatedQueryElements() : void
{
$uri = 'http://www.test-uri.com/path/here?id=123&ab=c&id=456#fragi';
$expected = 'http://www.test-uri.com/path/here?id=456&ab=c#fragi';
$uri = '/path/here?id=123&ab=c&id=456#fragi';
$expected = '/path/here?id=456&ab=c#fragi';
UriFactory::setupUriBuilder(new HttpUri($uri));
@ -216,9 +216,9 @@ final class UriFactoryTest extends \PHPUnit\Framework\TestCase
*/
public function testVariableUnescape() : void
{
$uri = 'http://www.test-uri.com/path/here?id=123&ab=c#fragi';
$uri = '/path/here?id=123&ab=c#fragi';
$escaped = '{/base}{/rootPath}{/}?id=\{\?id\}&ab={?ab}#{#}';
$unescaped = 'http://www.test-uri.com/path/here?id={?id}&ab=c#fragi';
$unescaped = '/path/here?id={?id}&ab=c#fragi';
UriFactory::setupUriBuilder(new HttpUri($uri));
@ -232,7 +232,7 @@ final class UriFactoryTest extends \PHPUnit\Framework\TestCase
*/
public function testMissingQueryIdentifier() : void
{
$uri = 'http://www.test-uri.com/path/here?id=123&ab=c#fragi';
$uri = '/path/here?id=123&ab=c#fragi';
UriFactory::setupUriBuilder(new HttpUri($uri));

View File

@ -170,8 +170,8 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
public function testGetCurrency() : void
{
$view = new View($this->app->l11nManager, null, new HttpResponse(Localization::fromLanguage('en')));
self::assertEquals('USD 1.23', $view->getCurrency(1.2345, 'medium'));
self::assertEquals('USD 1.235', $view->getCurrency(1.2345, 'long'));
self::assertEquals('USD 1.23', $view->getCurrency(1.2345, 'USD'));
self::assertEquals('USD 1.235', $view->getCurrency(1.2345, 'USD'));
$this->app->l11nManager->loadLanguage('en', '0', ['0' => ['CurrencyK' => 'K']]);
self::assertEquals('K$ 12.345', $view->getCurrency(12345.0, 'long', '$', 1000));