This commit is contained in:
Dennis Eichhorn 2024-02-25 00:38:41 +00:00
parent e7b708185e
commit 405638417e
63 changed files with 1741 additions and 826 deletions

64
.github/ISSUE_TEMPLATE/bugs.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug"]
assignees:
- spl1nes
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
value: "A bug happened!"
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of our software are you running?
options:
- Alpha (Default)
default: 0
validations:
required: true
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Firefox
- Chrome
- Safari
- Opera
- Microsoft Edge
- Other
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com)
options:
- label: I agree to follow this project's Code of Conduct
required: true

View File

@ -85,14 +85,34 @@ final class TesseractOcr
*
* @since 1.0.0
*/
public function parseImage(string $image, array $languages = ['eng'], int $psm = 3, int $oem = 3) : string
public function parseImage(string $image, array $languages = ['eng', 'deu'], int $psm = 3, int $oem = 3) : string
{
$temp = \tempnam(\sys_get_temp_dir(), 'oms_ocr_');
if ($temp === false) {
return '';
}
$extension = 'png';
try {
// Tesseract needs higher dpi to work properly (identify + adjust if necessary)
$dpi = (int) \trim(\implode('', SystemUtils::runProc(
'identify',
'-quiet -format "%x" ' . $image
)));
if ($dpi < 300) {
$split = \explode('.', $image);
$extension = \end($split);
SystemUtils::runProc(
'convert',
'-units PixelsPerInch ' . $image . ' -resample 300 ' . $temp . '.' . $extension
);
$image = $temp . '.' . $extension;
}
// Do actual parsing
SystemUtils::runProc(
self::$bin,
$image . ' '
@ -100,12 +120,20 @@ final class TesseractOcr
. ' -c preserve_interword_spaces=1'
. ' --psm ' . $psm
. ' --oem ' . $oem
. ' -l ' . \implode('+', $languages)
. (empty($languages) ? '' : ' -l ' . \implode('+', $languages))
);
} catch (\Throwable $_) {
if (\is_file($temp . '.' . $extension)) {
\unlink($temp . '.' . $extension);
}
return '';
}
if (\is_file($temp . '.' . $extension)) {
\unlink($temp . '.' . $extension);
}
$filepath = \is_file($temp . '.txt')
? $temp . '.txt'
: $temp;
@ -120,11 +148,7 @@ final class TesseractOcr
$parsed = \file_get_contents($filepath);
if ($parsed === false) {
// @codeCoverageIgnoreStart
\unlink($temp);
return '';
// @codeCoverageIgnoreEnd
$parsed = '';
}
\unlink($filepath);

View File

@ -35,14 +35,6 @@ abstract class BuilderAbstract
*/
protected bool $isReadOnly = false;
/**
* Grammar.
*
* @var GrammarAbstract
* @since 1.0.0
*/
protected GrammarAbstract $grammar;
/**
* Database connection.
*

View File

@ -15,7 +15,6 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database;
use phpOMS\Contract\SerializableInterface;
use phpOMS\DataStorage\Database\Query\Column;
use phpOMS\DataStorage\Database\Query\ColumnName;
use phpOMS\DataStorage\Database\Query\Parameter;
@ -61,22 +60,6 @@ abstract class GrammarAbstract
*/
public string $systemIdentifierEnd = '"';
/**
* And operator.
*
* @var string
* @since 1.0.0
*/
public string $and = 'AND';
/**
* Or operator.
*
* @var string
* @since 1.0.0
*/
public string $or = 'OR';
/**
* Special keywords.
*
@ -88,9 +71,6 @@ abstract class GrammarAbstract
'MAX(',
'MIN(',
'SUM(',
'DATE(',
'YEAR(',
'MONTH(',
];
/**
@ -116,30 +96,7 @@ abstract class GrammarAbstract
}
/**
* Compile to query.
*
* @param BuilderAbstract $query Builder
*
* @return string
*
* @since 1.0.0
*/
public function compileQuery(BuilderAbstract $query) : string
{
$components = $this->compileComponents($query);
$queryString = '';
foreach ($components as $component) {
if ($component !== '') {
$queryString .= $component . ' ';
}
}
return \substr($queryString, 0, -1) . ';';
}
/**
* Compile post querys.
* Compile post queries.
*
* These are queries, which should be run after the main query (e.g. table alters, trigger definitions etc.)
*
@ -149,7 +106,7 @@ abstract class GrammarAbstract
*
* @since 1.0.0
*/
public function compilePostQuerys(BuilderAbstract $query) : array
public function compilePostQueries(BuilderAbstract $query) : array
{
return [];
}
@ -165,7 +122,7 @@ abstract class GrammarAbstract
*
* @since 1.0.0
*/
abstract protected function compileComponents(BuilderAbstract $query) : array;
abstract public function compileComponents(BuilderAbstract $query) : array;
/**
* Get date format.
@ -191,23 +148,20 @@ abstract class GrammarAbstract
*
* @since 1.0.0
*/
protected function expressionizeTableColumn(array $elements, bool $column = true) : string
public function expressionizeTableColumn(array $elements, bool $column = true) : string
{
$expression = '';
foreach ($elements as $key => $element) {
if (\is_string($element)) {
$expression .= $this->compileSystem($element)
. (\is_string($key) ? ' as ' . $key : '') . ', ';
$expression .= $this->compileSystem($element) . (\is_string($key) ? ' AS ' . $key : '') . ', ';
} elseif (\is_int($element)) {
// example: select 1
$expression .= $element . ', ';
} elseif ($element instanceof \Closure) {
$expression .= $element() . (\is_string($key) ? ' as ' . $key : '') . ', ';
} elseif ($element instanceof BuilderAbstract) {
$expression .= $element->toSql() . (\is_string($key) ? ' as ' . $key : '') . ', ';
} elseif (\is_int($element)) {
$expression .= $element . ', ';
$expression .= $element->toSql() . (\is_string($key) ? ' AS ' . $key : '') . ', ';
} elseif ($element instanceof \Closure) {
$expression .= $element() . (\is_string($key) ? ' AS ' . $key : '') . ', ';
} else {
throw new \InvalidArgumentException();
}
@ -241,9 +195,9 @@ abstract class GrammarAbstract
$identifierEnd = '';
} elseif ((\stripos($system, '.')) !== false) {
// This is actually slower than \explode(), despite knowing the first index
//$split = [\substr($system, 0, $pos), \substr($system, $pos + 1)];
// $split = [\substr($system, 0, $pos), \substr($system, $pos + 1)];
// Faster! But might requires more memory?
// Faster! But might require more memory?
$split = \explode('.', $system);
$identifierTwoStart = $identifierStart;
@ -298,8 +252,6 @@ abstract class GrammarAbstract
return (string) ((int) $value);
} elseif (\is_float($value)) {
return \rtrim(\rtrim(\number_format($value, 5, '.', ''), '0'), '.');
} elseif ($value instanceof Column) {
return '(' . \rtrim($this->compileColumnQuery($value), ';') . ')';
} elseif ($value instanceof ColumnName) {
return $this->compileSystem($value->name);
} elseif ($value instanceof BuilderAbstract) {
@ -316,18 +268,4 @@ abstract class GrammarAbstract
throw new \InvalidArgumentException(\gettype($value));
}
}
/**
* Compile column query.
*
* @param Column $column Where query
*
* @return string
*
* @since 1.0.0
*/
protected function compileColumnQuery(Column $column) : string
{
return $column->toSql();
}
}

View File

@ -291,6 +291,8 @@ final class ReadMapper extends DataMapperAbstract
if (!empty($this->indexedBy)) {
return $indexed;
} elseif ($this->type === MapperType::GET_ALL) {
return $objs;
}
$countResults = \count($objs);
@ -377,6 +379,16 @@ final class ReadMapper extends DataMapperAbstract
$query ??= $this->getQuery();
try {
/*
\phpOMS\Log\FileLogger::getInstance()->info(
\phpOMS\Log\FileLogger::MSG_FULL, [
'message' => $query->toSql(),
'line' => __LINE__,
'file' => self::class,
]
);
*/
$sth = $this->db->con->prepare($query->toSql());
if ($sth === false) {
yield [];
@ -559,6 +571,7 @@ final class ReadMapper extends DataMapperAbstract
// This is necessary for special cases, e.g. when joining in the other direction
// Example: Show all profiles who have written a news article.
// "with()" only allows to go from articles to accounts but we want to go the other way
//
// @feature Create join functionality for mappers which supports joining and filtering based on other tables
// Example: show all profiles which have written a news article
// https://github.com/Karaka-Management/phpOMS/issues/253
@ -1124,8 +1137,9 @@ final class ReadMapper extends DataMapperAbstract
$refClass = null;
// @todo check if there are more cases where the relation is already loaded with joins etc.
// there can be pseudo hasMany elements like localizations. They are hasMany but these are already loaded with joins!
// @todo Check if there are more cases where the relation is already loaded with joins etc.
// There can be pseudo hasMany elements like localizations.
// They are hasMany but these are already loaded with joins!
foreach ($this->with as $member => $withData) {
if (isset($this->mapper::HAS_MANY[$member])) {
$many = $this->mapper::HAS_MANY[$member];

View File

@ -26,6 +26,9 @@ use phpOMS\Utils\ArrayUtils;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Lock data for concurrency (e.g. table row lock or heartbeat)
* https://github.com/Karaka-Management/Karaka/issues/152
*/
final class WriteMapper extends DataMapperAbstract
{

View File

@ -18,6 +18,7 @@ use phpOMS\Algorithm\Graph\DependencyResolver;
use phpOMS\Contract\SerializableInterface;
use phpOMS\DataStorage\Database\BuilderAbstract;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
use phpOMS\DataStorage\Database\Query\Grammar\Grammar;
/**
* Database query builder.
@ -26,9 +27,22 @@ use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @question Consider to delete the builder but create a Select, Insert, ... builder
* Then directly call the compileSelect + compileFrom ... from the toSql
* This way the object generated would be much slimmer since we don't need to initialize empty data for
* Insert etc. We also wouldn't have to call compileComponents since this would happen directly in toSql().
*/
class Builder extends BuilderAbstract
{
/**
* Grammar.
*
* @var Grammar
* @since 1.0.0
*/
protected Grammar $grammar;
/**
* Log queries.
*
@ -62,7 +76,9 @@ class Builder extends BuilderAbstract
public array $updates = [];
/**
* Stupid work around because value needs to be not null for it to work in Grammar.
* Deletes.
*
* @todo Find fix for stupid work around because value needs to be not null for it to work in Grammar.
*
* @var array
* @since 1.0.0
@ -354,7 +370,16 @@ class Builder extends BuilderAbstract
$this->resolveJoinDependencies();
}
$query = $this->grammar->compileQuery($this);
$components = $this->grammar->compileComponents($this);
$queryString = '';
foreach ($components as $component) {
if ($component !== '') {
$queryString .= $component . ' ';
}
}
$query = \substr($queryString, 0, -1) . ';';
if (self::$log) {
\phpOMS\Log\FileLogger::getInstance()->debug($query);
@ -399,7 +424,7 @@ class Builder extends BuilderAbstract
$resolved = DependencyResolver::resolve($dependencies);
// cyclomatic dependencies
// cyclic dependencies
if ($resolved === null) {
return;
}
@ -816,76 +841,88 @@ class Builder extends BuilderAbstract
*/
public function __toString()
{
return $this->grammar->compileQuery($this);
}
$components = $this->grammar->compileComponents($this);
$queryString = '';
/**
* Find query.
*
* @return void
*
* @since 1.0.0
*/
public function find() : void
{
foreach ($components as $component) {
if ($component !== '') {
$queryString .= $component . ' ';
}
}
return \substr($queryString, 0, -1) . ';';
}
/**
* Count results.
*
* @param string $table Table to count the result set
* @param string $column Table to count the result set
*
* @return Builder
*
* @since 1.0.0
*/
public function count(string $table = '*') : self
public function count(string $column = '*', ?string $as = null) : self
{
return $this->select('COUNT(' . $table . ')');
return $as === null
? $this->select('COUNT(' . $column . ')')
: $this->selectAs('COUNT(' . $column . ')', $as);
}
/**
* Select minimum.
*
* @return void
* @return Builder
*
* @since 1.0.0
*/
public function min() : void
public function min(string $column = '*', ?string $as = null) : self
{
return $as === null
? $this->select('MIN(' . $column . ')')
: $this->selectAs('MIN(' . $column . ')', $as);
}
/**
* Select maximum.
*
* @return void
* @return Builder
*
* @since 1.0.0
*/
public function max() : void
public function max(string $column = '*', ?string $as = null) : self
{
return $as === null
? $this->select('MAX(' . $column . ')')
: $this->selectAs('MAX(' . $column . ')', $as);
}
/**
* Select sum.
*
* @return void
* @return Builder
*
* @since 1.0.0
*/
public function sum() : void
public function sum(string $column = '*', ?string $as = null) : self
{
return $as === null
? $this->select('SUM(' . $column . ')')
: $this->selectAs('SUM(' . $column . ')', $as);
}
/**
* Select average.
*
* @return void
* @return Builder
*
* @since 1.0.0
*/
public function avg() : void
public function avg(string $column = '*', ?string $as = null) : self
{
return $as === null
? $this->select('AVG(' . $column . ')')
: $this->selectAs('AVG(' . $column . ')', $as);
}
/**
@ -1059,28 +1096,6 @@ class Builder extends BuilderAbstract
return $this;
}
/**
* Increment value.
*
* @return void
*
* @since 1.0.0
*/
public function increment() : void
{
}
/**
* Decrement value.
*
* @return void
*
* @since 1.0.0
*/
public function decrement() : void
{
}
/**
* Join.
*
@ -1282,7 +1297,7 @@ class Builder extends BuilderAbstract
* @param string|array $columns Columns to join on
* @param null|string|array $operator Comparison operator
* @param null|string|array $values Values to compare with
* @param string|array $boolean Concatonator
* @param string|array $boolean Concatenation
* @param null|string $table Table this belongs to
*
* @return Builder
@ -1354,29 +1369,16 @@ class Builder extends BuilderAbstract
return $this->on($columns, $operator, $values, 'and');
}
/**
* Merging query.
*
* Merging query in order to remove database query volume
*
* @return Builder
*
* @since 1.0.0
*/
public function merge() : self
{
return clone($this);
}
/**
* {@inheritdoc}
*/
public function execute() : ?\PDOStatement
{
$sth = null;
$sql = '';
try {
$sth = $this->connection->con->prepare($this->toSql());
$sth = $this->connection->con->prepare($sql = $this->toSql());
if ($sth === false) {
return null;
}
@ -1392,7 +1394,7 @@ class Builder extends BuilderAbstract
// @codeCoverageIgnoreStart
\phpOMS\Log\FileLogger::getInstance()->error(
\phpOMS\Log\FileLogger::MSG_FULL, [
'message' => $t->getMessage() . ':' . $this->toSql(),
'message' => $t->getMessage() . ':' . $sql,
'line' => __LINE__,
'file' => self::class,
]
@ -1442,8 +1444,6 @@ class Builder extends BuilderAbstract
{
if (\is_string($column)) {
return $column;
} elseif ($column instanceof Column) {
return $column->getColumn();
} elseif ($column instanceof SerializableInterface) {
return $column->serialize();
} elseif ($column instanceof self) {

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Column extends Builder
{
}

View File

@ -0,0 +1,67 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Concat extends Builder
{
public string $delim = '';
public string $as = '';
/**
* Constructor.
*
* @param ConnectionAbstract $connection Database connection
*
* @since 1.0.0
*/
public function __construct(ConnectionAbstract $connection)
{
parent::__construct($connection);
$this->type = QueryType::SELECT;
}
public function columns(string $as, string $delim, ...$columns) : void
{
$this->delim = $delim;
$this->as = $as;
$this->select($columns);
}
/**
* {@inheritdoc}
*/
public function toSql() : string
{
$query = $this->grammar->compileConcat($this, $this->selects);
if (self::$log) {
\phpOMS\Log\FileLogger::getInstance()->debug($query);
}
return $query;
}
}

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Count extends Builder
{
}

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Expression extends Builder
{
}

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class From extends Builder
{
}

View File

@ -17,10 +17,7 @@ namespace phpOMS\DataStorage\Database\Query\Grammar;
use phpOMS\DataStorage\Database\BuilderAbstract;
use phpOMS\DataStorage\Database\GrammarAbstract;
use phpOMS\DataStorage\Database\Query\Builder;
use phpOMS\DataStorage\Database\Query\ColumnName;
use phpOMS\DataStorage\Database\Query\From;
use phpOMS\DataStorage\Database\Query\QueryType;
use phpOMS\DataStorage\Database\Query\Where;
/**
* Database query grammar.
@ -37,7 +34,7 @@ class Grammar extends GrammarAbstract
*
* @throws \InvalidArgumentException
*/
protected function compileComponents(BuilderAbstract $query) : array
public function compileComponents(BuilderAbstract $query) : array
{
/** @var Builder $query */
@ -183,6 +180,21 @@ class Grammar extends GrammarAbstract
return '';
}
/**
* Create concat
*
* @param Concat $query Builder
* @param array $columns Columns
*
* @return string
*
* @since 1.0.0
*/
public function compileConcat(\phpOMS\DataStorage\Database\Query\Concat $query, array $columns) : string
{
return 'CONCAT(' . $this->expressionizeTableColumn($columns) . ') AS ' . $query->as;
}
/**
* Compile select.
*
@ -244,14 +256,14 @@ class Grammar extends GrammarAbstract
* Compile where.
*
* @param Builder $query Builder
* @param array $wheres Where elmenets
* @param array $wheres Where elements
* @param bool $first Is first element (useful for nesting)
*
* @return string
*
* @since 1.0.0
*/
protected function compileWheres(Builder $query, array $wheres, bool $first = true) : string
public function compileWheres(Builder $query, array $wheres, bool $first = true) : string
{
$expression = '';
@ -283,58 +295,46 @@ class Grammar extends GrammarAbstract
protected function compileWhereElement(array $element, Builder $query, bool $first = true) : string
{
$expression = '';
$prefix = '';
if (!$first) {
$expression = ' ' . \strtoupper($element['boolean']) . ' ';
$prefix = ' ' . \strtoupper($element['boolean']) . ' ';
}
if (\is_string($element['column'])) {
$expression .= $this->compileSystem($element['column']);
} elseif ($element['column'] instanceof \Closure) {
$expression .= $element['column']();
} elseif ($element['column'] instanceof Where) {
$where = \rtrim($this->compileWhereQuery($element['column']), ';');
$expression .= '(' . (\str_starts_with($where, 'WHERE ') ? \substr($where, 6) : $where) . ')';
} elseif ($element['column'] instanceof Builder) {
$expression .= '(' . \rtrim($element['column']->toSql(), ';') . ')';
} elseif ($element['column'] instanceof \Closure) {
$expression .= $element['column']();
}
if (isset($element['value']) && (!empty($element['value']) || !\is_array($element['value']))) {
// Handle null for IN (...)
// This is not allowed and must be written as (IN (...) OR IS NULL)
$isArray = \is_array($element['value']);
$hasNull = false;
if ($isArray && ($key = \array_search(null, $element['value'], true)) !== false) {
$hasNull = true;
unset($element['value'][$key]);
if (empty($element['value'])) {
$element['operator'] = '=';
$element['value'] = null;
}
}
if (isset($element['value']) && (!empty($element['value']) || !$isArray)) {
$expression .= ' ' . \strtoupper($element['operator']) . ' ' . $this->compileValue($query, $element['value']);
if ($hasNull) {
$expression = '(' . $expression . ' OR ' . $this->compileSystem($element['column']) . ' IS NULL)';
}
} elseif ($element['value'] === null && !($element['column'] instanceof Builder)) {
$operator = $element['operator'] === '=' ? 'IS' : 'IS NOT';
$expression .= ' ' . $operator . ' ' . $this->compileValue($query, $element['value']);
}
return $expression;
}
/**
* Compile where query.
*
* @param Where $where Where query
*
* @return string
*
* @since 1.0.0
*/
protected function compileWhereQuery(Where $where) : string
{
return $where->toSql();
}
/**
* Compile from query.
*
* @param From $from Where query
*
* @return string
*
* @since 1.0.0
*/
protected function compileFromQuery(From $from) : string
{
return $from->toSql();
return $prefix . $expression;
}
/**
@ -445,18 +445,16 @@ class Grammar extends GrammarAbstract
}
if (\is_string($element['column'])) {
// handle bug when no table is specified in the where column
// @bug Handle bug when no table is specified in the where column
if (\count($query->from) === 1 && \stripos($element['column'], '.') === false) {
$element['column'] = $query->from[0] . '.' . $element['column'];
}
$expression .= $this->compileSystem($element['column']);
} elseif ($element['column'] instanceof \Closure) {
$expression .= $element['column']();
} elseif ($element['column'] instanceof Builder) {
$expression .= '(' . $element['column']->toSql() . ')';
} elseif ($element['column'] instanceof Where) {
$expression .= '(' . \rtrim($this->compileWhereQuery($element['column']), ';') . ')';
} elseif ($element['column'] instanceof \Closure) {
$expression .= $element['column']();
}
// @bug The on part of a join doesn't allow string values because they conflict with column name

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query\Grammar
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query\Grammar;
/**
* Grammar interface.
*
* @package phpOMS\DataStorage\Database\Query\Grammar
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
interface GrammarInterface
{
}

View File

@ -62,4 +62,22 @@ class SQLiteGrammar extends Grammar
return 'SELECT ' . $expression . ' ' . $this->compileFrom($query, $query->from) . ' ORDER BY RANDOM() ' . $this->compileLimit($query, $query->limit ?? 1);
}
/**
* Create concat
*
* @param Concat $query Builder
* @param array $columns Columns
*
* @return string
*
* @since 1.0.0
*/
public function compileConcat(\phpOMS\DataStorage\Database\Query\Concat $query, array $columns) : string
{
$sql = $this->expressionizeTableColumn($columns);
$sql = \str_replace(',', ' ||', $sql);
return $sql . ' AS ' . $query->as;
}
}

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Into extends Builder
{
}

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Query
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Query;
/**
* Database query builder.
*
* @package phpOMS\DataStorage\Database\Query
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Select extends Builder
{
}

View File

@ -38,4 +38,19 @@ class Where extends Builder
parent::__construct($connection);
$this->type = QueryType::SELECT;
}
/**
* {@inheritdoc}
*/
public function toSql() : string
{
$query = $this->grammar->compileWheres($this, $this->wheres);
$query = \str_starts_with($query, 'WHERE ') ? \substr($query, 6) : $query;
if (self::$log) {
\phpOMS\Log\FileLogger::getInstance()->debug($query);
}
return $query;
}
}

View File

@ -16,6 +16,7 @@ namespace phpOMS\DataStorage\Database\Schema;
use phpOMS\DataStorage\Database\BuilderAbstract;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
use phpOMS\DataStorage\Database\Schema\Grammar\Grammar;
/**
* Database query builder.
@ -29,6 +30,14 @@ use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
*/
class Builder extends BuilderAbstract
{
/**
* Grammar.
*
* @var Grammar
* @since 1.0.0
*/
protected Grammar $grammar;
/**
* Table to create.
*
@ -260,7 +269,7 @@ class Builder extends BuilderAbstract
* @param bool $isNullable Can be null
* @param bool $isPrimary Is a primary field
* @param bool $isUnique Is a unique field
* @param bool $autoincrement Autoincrements
* @param bool $autoincrement Auto increments
* @param string $foreignTable Foreign table (in case of foreign key)
* @param string $foreignKey Foreign key
* @param array $meta Meta data
@ -335,9 +344,10 @@ class Builder extends BuilderAbstract
public function execute() : ?\PDOStatement
{
$sth = null;
$sql = '';
try {
$sth = $this->connection->con->prepare($this->toSql());
$sth = $this->connection->con->prepare($sql = $this->toSql());
if ($sth === false) {
return null;
}
@ -347,14 +357,19 @@ class Builder extends BuilderAbstract
if ($this->hasPostQuery) {
$sqls = $this->grammar->compilePostQueries($this);
foreach ($sqls as $sql) {
$this->connection->con->exec($sql);
foreach ($sqls as $post) {
$this->connection->con->exec($post);
}
}
} catch (\Throwable $t) {
// @codeCoverageIgnoreStart
\var_dump($t->getMessage());
\var_dump($this->toSql());
\phpOMS\Log\FileLogger::getInstance()->error(
\phpOMS\Log\FileLogger::MSG_FULL, [
'message' => $t->getMessage() . ':' . $sql,
'line' => __LINE__,
'file' => self::class,
]
);
$sth = null;
// @codeCoverageIgnoreEnd
@ -368,6 +383,15 @@ class Builder extends BuilderAbstract
*/
public function toSql() : string
{
return $this->grammar->compileQuery($this);
$components = $this->grammar->compileComponents($this);
$queryString = '';
foreach ($components as $component) {
if ($component !== '') {
$queryString .= $component . ' ';
}
}
return \substr($queryString, 0, -1) . ';';
}
}

View File

@ -32,7 +32,7 @@ class Grammar extends GrammarAbstract
/**
* {@inheritdoc}
*/
protected function compileComponents(BuilderAbstract $query) : array
public function compileComponents(BuilderAbstract $query) : array
{
/** @var SchemaBuilder $query */

View File

@ -1,27 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\DataStorage\Database\Schema
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Schema\Grammar;
/**
* Grammar interface.
*
* @package phpOMS\DataStorage\Database\Schema\Grammar
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
interface GrammarInterface
{
}

View File

@ -26,6 +26,9 @@ use phpOMS\DataStorage\Database\Schema\Table;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @feature Implement schema modification grammar (alter tables)
* https://github.com/Karaka-Management/phpOMS/issues/275
*/
class SchemaMapper
{

View File

@ -106,9 +106,9 @@ final class HttpSession implements SessionInterface
\session_start();
// @codeCoverageIgnoreEnd
} else {
FileLogger::getInstance()->error(
FileLogger::getInstance()->warning(
FileLogger::MSG_FULL, [
'message' => 'Bad application flow.',
'message' => 'Headers already sent.',
'line' => __LINE__,
'file' => self::class,
]

View File

@ -44,6 +44,479 @@ trait ISO3166Trait
return self::getByName($code3);
}
/**
* Get country from language.
*
* @param string $language Language 2 code
*
* @return array
*
* @since 1.0.0
*/
public static function countryFromLanguage(string $language) : array
{
switch (\strtolower($language)) {
case ISO639x1Enum::_PS:
return [
self::_AFG,
];
case ISO639x1Enum::_UZ:
return [
self::_AFG, self::_UZB,
];
case ISO639x1Enum::_TK:
return [
self::_AFG, self::_TKM,
];
case ISO639x1Enum::_SV:
return [
self::_ALA, self::_FIN, self::_SWE,
];
case ISO639x1Enum::_SQ:
return [
self::_ALB, self::_MNE,
];
case ISO639x1Enum::_AR:
return [
self::_DZA, self::_BHR, self::_TCD, self::_COM, self::_DJI, self::_EGY, self::_ERI, self::_ETH, self::_IRQ, self::_ISR, self::_JOR, self::_KWT, self::_LBN, self::_LBY, self::_MRT, self::_MAR, self::_OMN, self::_PSE, self::_QAT, self::_SAU, self::_SOM, self::_SDN, self::_SYR, self::_TUN, self::_ARE, self::_ESH, self::_YEM,
];
case ISO639x1Enum::_EN:
return [
self::_USA, self::_ASM, self::_AIA, self::_ATA, self::_ATG, self::_AUS, self::_BHS, self::_BRB, self::_BLZ, self::_BMU, self::_BES, self::_BWA, self::_IOT, self::_CMR, self::_CAN, self::_CYM, self::_CXR, self::_CCK, self::_COK, self::_CUW, self::_DMA, self::_ERI, self::_FLK, self::_FJI, self::_GMB, self::_GHA, self::_GIB, self::_GRD, self::_GUM, self::_GGY, self::_GUY, self::_HMD, self::_HKG, self::_IND, self::_IRL, self::_IMN, self::_JAM, self::_JEY, self::_KEN, self::_KIR, self::_LSO, self::_LBR, self::_MWI, self::_MLT, self::_MHL, self::_MUS, self::_FSM, self::_MSR, self::_NAM, self::_NRU, self::_NZL, self::_NGA, self::_NIU, self::_NFK, self::_MNP, self::_PAK, self::_PLW, self::_PNG, self::_PHL, self::_PCN, self::_PRI, self::_RWA, self::_SHN, self::_KNA, self::_LCA, self::_MAF, self::_VCT, self::_WSM, self::_SYC, self::_SLE, self::_SGP, self::_SXM, self::_SLB, self::_SOM, self::_ZAF, self::_SGS, self::_SSD, self::_LKA, self::_SDN, self::_SWZ, self::_TZA, self::_TKL, self::_TON, self::_TTO, self::_TCA, self::_TUV, self::_UGA, self::_GBR, self::_UMI, self::_VUT, self::_VGB, self::_VIR, self::_ZMB, self::_ZWE,
];
case ISO639x1Enum::_SM:
return [
self::_ASM, self::_WSM,
];
case ISO639x1Enum::_CA:
return [
self::_AND,
];
case ISO639x1Enum::_PT:
return [
self::_AGO, self::_BRA, self::_CPV, self::_GNQ, self::_GNB, self::_MAC, self::_MOZ, self::_PRT, self::_STP, self::_TLS,
];
case ISO639x1Enum::_RU:
return [
self::_ATA, self::_ARM, self::_AZE, self::_BLR, self::_KAZ, self::_KGZ, self::_RUS, self::_TJK, self::_TKM, self::_UZB,
];
case ISO639x1Enum::_ES:
return [
self::_ARG, self::_BOL, self::_CHL, self::_COL, self::_CRI, self::_CUB, self::_DOM, self::_ECU, self::_SLV, self::_GNQ, self::_GUM, self::_GTM, self::_HND, self::_MEX, self::_NIC, self::_PAN, self::_PRY, self::_PER, self::_PRI, self::_ESP, self::_USA, self::_URY, self::_VEN, self::_ESH,
];
case ISO639x1Enum::_GN:
return [
self::_ARG, self::_PRY,
];
case ISO639x1Enum::_HY:
return [
self::_ARM, self::_AZE,
];
case ISO639x1Enum::_NL:
return [
self::_ABW, self::_BEL, self::_BES, self::_CUW, self::_NLD, self::_MAF, self::_SXM, self::_SUR,
];
case ISO639x1Enum::_DE:
return [
self::_DEU, self::_AUT, self::_BEL, self::_LIE, self::_LUX, self::_CHE,
];
case ISO639x1Enum::_AZ:
return [
self::_AZE,
];
case ISO639x1Enum::_BN:
return [
self::_BGD,
];
case ISO639x1Enum::_BE:
return [
self::_BLR,
];
case ISO639x1Enum::_FR:
return [
self::_BEL, self::_BEN, self::_BFA, self::_BDI, self::_CMR, self::_CAN, self::_CAF, self::_TCD, self::_COM, self::_COG, self::_COD, self::_CIV, self::_DJI, self::_GNQ, self::_FRA, self::_GUF, self::_PYF, self::_ATF, self::_GAB, self::_GLP, self::_GGY, self::_GIN, self::_HTI, self::_JEY, self::_LBN, self::_LUX, self::_MDG, self::_MLI, self::_MTQ, self::_MRT, self::_MUS, self::_MYT, self::_MCO, self::_NCL, self::_NER, self::_REU, self::_RWA, self::_BLM, self::_MAF, self::_SPM, self::_SEN, self::_SYC, self::_CHE, self::_TGO, self::_VUT, self::_WLF,
];
case ISO639x1Enum::_DZ:
return [
self::_BTN,
];
case ISO639x1Enum::_QU:
return [
self::_BOL, self::_PER,
];
case ISO639x1Enum::_AY:
return [
self::_BOL, self::_PER,
];
case ISO639x1Enum::_BS:
return [
self::_BIH, self::_MNE, self::_XXK,
];
case ISO639x1Enum::_HR:
return [
self::_BIH, self::_HRV, self::_MNE,
];
case ISO639x1Enum::_SR:
return [
self::_BIH, self::_MNE, self::_SRB,
];
case ISO639x1Enum::_TN:
return [
self::_BWA, self::_ZAF,
];
case ISO639x1Enum::_NO:
return [
self::_BVT, self::_NOR, self::_SJM,
];
case ISO639x1Enum::_MS:
return [
self::_BRN, self::_MYS, self::_SGP,
];
case ISO639x1Enum::_BG:
return [
self::_BGR,
];
case ISO639x1Enum::_RN:
return [
self::_BDI,
];
case ISO639x1Enum::_KM:
return [
self::_KHM,
];
case ISO639x1Enum::_SG:
return [
self::_CAF,
];
case ISO639x1Enum::_ZH:
return [
self::_CHN, self::_HKG, self::_MAC, self::_PLW, self::_SGP, self::_TWN,
];
case ISO639x1Enum::_LN:
return [
self::_COG, self::_COD,
];
case ISO639x1Enum::_KG:
return [
self::_COG, self::_COD,
];
case ISO639x1Enum::_SW:
return [
self::_COG, self::_COD, self::_KEN, self::_TZA, self::_UGA,
];
case ISO639x1Enum::_PA:
return [
self::_CUW,
];
case ISO639x1Enum::_EL:
return [
self::_CYP, self::_GRC,
];
case ISO639x1Enum::_TR:
return [
self::_CYP, self::_TUR, self::_XXK,
];
case ISO639x1Enum::_CS:
return [
self::_CZE,
];
case ISO639x1Enum::_SK:
return [
self::_CZE, self::_SVK,
];
case ISO639x1Enum::_DA:
return [
self::_DNK,
];
case ISO639x1Enum::_SO:
return [
self::_DJI, self::_ETH, self::_SOM,
];
case ISO639x1Enum::_TI:
return [
self::_ERI, self::_ETH,
];
case ISO639x1Enum::_ET:
return [
self::_EST,
];
case ISO639x1Enum::_AM:
return [
self::_ETH,
];
case ISO639x1Enum::_OM:
return [
self::_ETH,
];
case ISO639x1Enum::_FO:
return [
self::_FRO,
];
case ISO639x1Enum::_FJ:
return [
self::_FJI,
];
case ISO639x1Enum::_HI:
return [
self::_FJI, self::_IND,
];
case ISO639x1Enum::_UR:
return [
self::_FJI, self::_PAK,
];
case ISO639x1Enum::_FI:
return [
self::_FIN,
];
case ISO639x1Enum::_TY:
return [
self::_PYF,
];
case ISO639x1Enum::_KA:
return [
self::_GEO,
];
case ISO639x1Enum::_KL:
return [
self::_GRL,
];
case ISO639x1Enum::_CH:
return [
self::_GUM, self::_MNP,
];
case ISO639x1Enum::_HT:
return [
self::_HTI,
];
case ISO639x1Enum::_IT:
return [
self::_VAT, self::_ITA, self::_SMR, self::_SOM, self::_CHE,
];
case ISO639x1Enum::_LA:
return [
self::_VAT,
];
case ISO639x1Enum::_HU:
return [
self::_HUN,
];
case ISO639x1Enum::_IS:
return [
self::_ISL,
];
case ISO639x1Enum::_ID:
return [
self::_IDN,
];
case ISO639x1Enum::_FA:
return [
self::_IRN,
];
case ISO639x1Enum::_KU:
return [
self::_IRQ,
];
case ISO639x1Enum::_GA:
return [
self::_IRL, self::_GBR,
];
case ISO639x1Enum::_GV:
return [
self::_IMN,
];
case ISO639x1Enum::_HE:
return [
self::_ISR,
];
case ISO639x1Enum::_JA:
return [
self::_JPN, self::_PLW,
];
case ISO639x1Enum::_KK:
return [
self::_KAZ,
];
case ISO639x1Enum::_KO:
return [
self::_PRK, self::_KOR,
];
case ISO639x1Enum::_KY:
return [
self::_KGZ,
];
case ISO639x1Enum::_LO:
return [
self::_LAO,
];
case ISO639x1Enum::_LV:
return [
self::_LVA,
];
case ISO639x1Enum::_ST:
return [
self::_LSO, self::_ZAF,
];
case ISO639x1Enum::_LT:
return [
self::_LTU,
];
case ISO639x1Enum::_LB:
return [
self::_LUX,
];
case ISO639x1Enum::_MK:
return [
self::_MKD,
];
case ISO639x1Enum::_MG:
return [
self::_MDG,
];
case ISO639x1Enum::_NY:
return [
self::_MWI,
];
case ISO639x1Enum::_DV:
return [
self::_MDV,
];
case ISO639x1Enum::_MT:
return [
self::_MLT,
];
case ISO639x1Enum::_MH:
return [
self::_MHL,
];
case ISO639x1Enum::_RO:
return [
self::_MDA, self::_ROU,
];
case ISO639x1Enum::_MN:
return [
self::_MNG,
];
case ISO639x1Enum::_MY:
return [
self::_MMR,
];
case ISO639x1Enum::_AF:
return [
self::_NAM, self::_ZAF,
];
case ISO639x1Enum::_NA:
return [
self::_NRU,
];
case ISO639x1Enum::_NE:
return [
self::_NPL,
];
case ISO639x1Enum::_MI:
return [
self::_NZL,
];
case ISO639x1Enum::_NB:
return [
self::_NOR,
];
case ISO639x1Enum::_NN:
return [
self::_NOR,
];
case ISO639x1Enum::_HO:
return [
self::_PNG,
];
case ISO639x1Enum::_PL:
return [
self::_POL,
];
case ISO639x1Enum::_RW:
return [
self::_RWA,
];
case ISO639x1Enum::_WO:
return [
self::_SEN,
];
case ISO639x1Enum::_TA:
return [
self::_SGP, self::_LKA,
];
case ISO639x1Enum::_SL:
return [
self::_SVN,
];
case ISO639x1Enum::_ZU:
return [
self::_ZAF,
];
case ISO639x1Enum::_XH:
return [
self::_ZAF,
];
case ISO639x1Enum::_TS:
return [
self::_ZAF,
];
case ISO639x1Enum::_SS:
return [
self::_ZAF, self::_SWZ,
];
case ISO639x1Enum::_VE:
return [
self::_ZAF,
];
case ISO639x1Enum::_SI:
return [
self::_LKA,
];
case ISO639x1Enum::_TG:
return [
self::_TJK,
];
case ISO639x1Enum::_TH:
return [
self::_THA,
];
case ISO639x1Enum::_TO:
return [
self::_TON,
];
case ISO639x1Enum::_UK:
return [
self::_UKR,
];
case ISO639x1Enum::_CY:
return [
self::_GBR,
];
case ISO639x1Enum::_GD:
return [
self::_GBR,
];
case ISO639x1Enum::_BI:
return [
self::_VUT,
];
case ISO639x1Enum::_VI:
return [
self::_VNM,
];
case ISO639x1Enum::_SN:
return [
self::_ZWE,
];
case ISO639x1Enum::_ND:
return [
self::_ZWE,
];
default:
return [];
}
}
/**
* Get countries in a region
*

View File

@ -75,6 +75,8 @@ class ISO4217CharEnum extends Enum
public const _CLP = 'CLP';
public const _CNY = 'CNY';
public const _CNH = 'CNH';
public const _RMB = 'RMB';
public const _COP = 'COP';
@ -403,4 +405,6 @@ class ISO4217CharEnum extends Enum
public const _XUA = 'XUA';
public const _ZMW = 'ZMW';
use ISO4217Trait;
}

View File

@ -93,6 +93,8 @@ class ISO4217DecimalEnum extends Enum
public const _CLP = 0;
public const _CNY = 2;
public const _CNH = 2;
public const _RMB = 2;
public const _COP = 2;

View File

@ -75,6 +75,8 @@ class ISO4217Enum extends Enum
public const _CLP = 'Pesos, Chile';
public const _CNY = 'Yuan Renminbi, China';
public const _CNH = 'Yuan Renminbi, China';
public const _RMB = 'Yuan Renminbi, China';
public const _COP = 'Pesos, Colombia';
@ -403,4 +405,6 @@ class ISO4217Enum extends Enum
public const _XUA = 'ADB Unit of Account';
public const _ZMW = 'kwacha, Zambian';
use ISO4217Trait;
}

View File

@ -93,6 +93,8 @@ class ISO4217NumEnum extends Enum
public const _CLP = '152';
public const _CNY = '156';
public const _CNH = '156';
public const _RMB = '156';
public const _COP = '170';
@ -393,4 +395,6 @@ class ISO4217NumEnum extends Enum
public const _ZMK = '894';
public const _ZWL = '932';
use ISO4217Trait;
}

View File

@ -83,6 +83,8 @@ class ISO4217SubUnitEnum extends Enum
public const _CLP = 100;
public const _CNY = 100;
public const _CNH = 100;
public const _RMB = 100;
public const _COP = 100;

View File

@ -75,6 +75,8 @@ class ISO4217SymbolEnum extends Enum
public const _CLP = '$';
public const _CNY = '¥';
public const _CNH = '¥';
public const _RMB = '¥';
public const _COP = '$';
@ -401,4 +403,6 @@ class ISO4217SymbolEnum extends Enum
public const _ZMW = 'ZK';
public const _KES = 'KSh';
use ISO4217Trait;
}

View File

@ -0,0 +1,483 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\Localization
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\Localization;
/**
* ISO 4217 country -> currency trait.
*
* @package phpOMS\Localization
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
trait ISO4217Trait
{
/**
* Get currency from country.
*
* @param string $country Country 2 code
*
* @return array
*
* @since 1.0.0
*/
public static function currencyFromCountry(string $country) : string
{
switch (\strtoupper($country)) {
case ISO3166TwoEnum::_AFG:
return self::_USD;
case ISO3166TwoEnum::_ALA:
return self::_EUR;
case ISO3166TwoEnum::_ALB:
return self::_EUR;
case ISO3166TwoEnum::_DZA:
return self::_DZD;
case ISO3166TwoEnum::_ASM:
return self::_USD;
case ISO3166TwoEnum::_AND:
return self::_EUR;
case ISO3166TwoEnum::_AGO:
return self::_AOA;
case ISO3166TwoEnum::_AIA:
return self::_XCD;
case ISO3166TwoEnum::_ATG:
return self::_XCD;
case ISO3166TwoEnum::_ARG:
return self::_ARS;
case ISO3166TwoEnum::_ARM:
return self::_AMD;
case ISO3166TwoEnum::_ABW:
return self::_AWG;
case ISO3166TwoEnum::_AUS:
return self::_AUD;
case ISO3166TwoEnum::_AUT:
return self::_EUR;
case ISO3166TwoEnum::_AZE:
return self::_AZM;
case ISO3166TwoEnum::_PRT:
return self::_EUR;
case ISO3166TwoEnum::_BHS:
return self::_BSD;
case ISO3166TwoEnum::_BHR:
return self::_BHD;
case ISO3166TwoEnum::_BGD:
return self::_BDT;
case ISO3166TwoEnum::_BRB:
return self::_BBD;
case ISO3166TwoEnum::_BLR:
return self::_BYR;
case ISO3166TwoEnum::_BEL:
return self::_EUR;
case ISO3166TwoEnum::_BLZ:
return self::_BZD;
case ISO3166TwoEnum::_BEN:
return self::_XOF;
case ISO3166TwoEnum::_BMU:
return self::_BMD;
case ISO3166TwoEnum::_BTN:
return self::_BTN;
case ISO3166TwoEnum::_BOL:
return self::_BOB;
case ISO3166TwoEnum::_BES:
return self::_ANG;
case ISO3166TwoEnum::_BIH:
return self::_BAM;
case ISO3166TwoEnum::_BWA:
return self::_BWP;
case ISO3166TwoEnum::_BRA:
return self::_BRL;
case ISO3166TwoEnum::_VGB:
return self::_USD;
case ISO3166TwoEnum::_BRN:
return self::_BND;
case ISO3166TwoEnum::_BGR:
return self::_EUR;
case ISO3166TwoEnum::_BFA:
return self::_XOF;
case ISO3166TwoEnum::_BDI:
return self::_BIF;
case ISO3166TwoEnum::_KHM:
return self::_KHR;
case ISO3166TwoEnum::_CMR:
return self::_XAF;
case ISO3166TwoEnum::_CAN:
return self::_CAD;
case ISO3166TwoEnum::_ESP:
return self::_EUR;
case ISO3166TwoEnum::_CPV:
return self::_CVE;
case ISO3166TwoEnum::_CYM:
return self::_KYD;
case ISO3166TwoEnum::_CAF:
return self::_XAF;
case ISO3166TwoEnum::_TCD:
return self::_XAF;
case ISO3166TwoEnum::_CHL:
return self::_CLP;
case ISO3166TwoEnum::_CHN:
return self::_CNY;
case ISO3166TwoEnum::_COL:
return self::_COP;
case ISO3166TwoEnum::_COM:
return self::_USD;
case ISO3166TwoEnum::_COG:
return self::_XAF;
case ISO3166TwoEnum::_COD:
return self::_CDF;
case ISO3166TwoEnum::_COK:
return self::_NZD;
case ISO3166TwoEnum::_CRI:
return self::_CRC;
case ISO3166TwoEnum::_HRV:
return self::_EUR;
case ISO3166TwoEnum::_CUW:
return self::_USD;
case ISO3166TwoEnum::_CYP:
return self::_EUR;
case ISO3166TwoEnum::_CZE:
return self::_CZK;
case ISO3166TwoEnum::_DNK:
return self::_DKK;
case ISO3166TwoEnum::_DJI:
return self::_DJF;
case ISO3166TwoEnum::_DMA:
return self::_XCD;
case ISO3166TwoEnum::_DOM:
return self::_DOP;
case ISO3166TwoEnum::_TLS:
return self::_USD;
case ISO3166TwoEnum::_ECU:
return self::_USD;
case ISO3166TwoEnum::_EGY:
return self::_EGP;
case ISO3166TwoEnum::_SLV:
return self::_USD;
case ISO3166TwoEnum::_GBR:
return self::_GBP;
case ISO3166TwoEnum::_GNQ:
return self::_XAF;
case ISO3166TwoEnum::_ERI:
return self::_ERN;
case ISO3166TwoEnum::_EST:
return self::_EUR;
case ISO3166TwoEnum::_ETH:
return self::_ETB;
case ISO3166TwoEnum::_FRO:
return self::_DKK;
case ISO3166TwoEnum::_FJI:
return self::_FJD;
case ISO3166TwoEnum::_FIN:
return self::_EUR;
case ISO3166TwoEnum::_FRA:
return self::_EUR;
case ISO3166TwoEnum::_GUF:
return self::_EUR;
case ISO3166TwoEnum::_PYF:
return self::_XPF;
case ISO3166TwoEnum::_GAB:
return self::_XAF;
case ISO3166TwoEnum::_GMB:
return self::_GMD;
case ISO3166TwoEnum::_GEO:
return self::_GEL;
case ISO3166TwoEnum::_DEU:
return self::_EUR;
case ISO3166TwoEnum::_GHA:
return self::_GHS;
case ISO3166TwoEnum::_GIB:
return self::_GIP;
case ISO3166TwoEnum::_GRC:
return self::_EUR;
case ISO3166TwoEnum::_GRL:
return self::_DKK;
case ISO3166TwoEnum::_GRD:
return self::_XCD;
case ISO3166TwoEnum::_GLP:
return self::_EUR;
case ISO3166TwoEnum::_GUM:
return self::_USD;
case ISO3166TwoEnum::_GTM:
return self::_GTQ;
case ISO3166TwoEnum::_GGY:
return self::_GBP;
case ISO3166TwoEnum::_GIN:
return self::_GNF;
case ISO3166TwoEnum::_GNB:
return self::_XOF;
case ISO3166TwoEnum::_GUY:
return self::_GYD;
case ISO3166TwoEnum::_HTI:
return self::_HTG;
case ISO3166TwoEnum::_NLD:
return self::_EUR;
case ISO3166TwoEnum::_HND:
return self::_HNL;
case ISO3166TwoEnum::_HKG:
return self::_HKD;
case ISO3166TwoEnum::_HUN:
return self::_HUF;
case ISO3166TwoEnum::_ISL:
return self::_ISK;
case ISO3166TwoEnum::_IND:
return self::_INR;
case ISO3166TwoEnum::_IDN:
return self::_IDR;
case ISO3166TwoEnum::_IRQ:
return self::_NID;
case ISO3166TwoEnum::_IRL:
return self::_EUR;
case ISO3166TwoEnum::_ISR:
return self::_ILS;
case ISO3166TwoEnum::_ITA:
return self::_EUR;
case ISO3166TwoEnum::_CIV:
return self::_XOF;
case ISO3166TwoEnum::_JAM:
return self::_JMD;
case ISO3166TwoEnum::_JPN:
return self::_JPY;
case ISO3166TwoEnum::_JEY:
return self::_GBP;
case ISO3166TwoEnum::_JOR:
return self::_JOD;
case ISO3166TwoEnum::_KAZ:
return self::_KZT;
case ISO3166TwoEnum::_KEN:
return self::_KES;
case ISO3166TwoEnum::_KIR:
return self::_AUD;
case ISO3166TwoEnum::_KOR:
return self::_KRW;
case ISO3166TwoEnum::_FSM:
return self::_USD;
case ISO3166TwoEnum::_KWT:
return self::_KWD;
case ISO3166TwoEnum::_KGZ:
return self::_KGS;
case ISO3166TwoEnum::_LAO:
return self::_LAK;
case ISO3166TwoEnum::_LVA:
return self::_EUR;
case ISO3166TwoEnum::_LBN:
return self::_LBP;
case ISO3166TwoEnum::_LSO:
return self::_LSL;
case ISO3166TwoEnum::_LBR:
return self::_LRD;
case ISO3166TwoEnum::_LBY:
return self::_LYD;
case ISO3166TwoEnum::_LIE:
return self::_CHF;
case ISO3166TwoEnum::_LTU:
return self::_EUR;
case ISO3166TwoEnum::_LUX:
return self::_EUR;
case ISO3166TwoEnum::_MAC:
return self::_MOP;
case ISO3166TwoEnum::_MKD:
return self::_EUR;
case ISO3166TwoEnum::_MDG:
return self::_MGA;
case ISO3166TwoEnum::_MWI:
return self::_MWK;
case ISO3166TwoEnum::_MYS:
return self::_MYR;
case ISO3166TwoEnum::_MDV:
return self::_MVR;
case ISO3166TwoEnum::_MLI:
return self::_XOF;
case ISO3166TwoEnum::_MLT:
return self::_EUR;
case ISO3166TwoEnum::_MHL:
return self::_USD;
case ISO3166TwoEnum::_MTQ:
return self::_EUR;
case ISO3166TwoEnum::_MRT:
return self::_MRO;
case ISO3166TwoEnum::_MUS:
return self::_MUR;
case ISO3166TwoEnum::_MYT:
return self::_EUR;
case ISO3166TwoEnum::_MEX:
return self::_MXN;
case ISO3166TwoEnum::_MDA:
return self::_MDL;
case ISO3166TwoEnum::_MCO:
return self::_EUR;
case ISO3166TwoEnum::_MNG:
return self::_MNT;
case ISO3166TwoEnum::_MNE:
return self::_EUR;
case ISO3166TwoEnum::_MSR:
return self::_XCD;
case ISO3166TwoEnum::_MAR:
return self::_MAD;
case ISO3166TwoEnum::_MOZ:
return self::_MZM;
case ISO3166TwoEnum::_NAM:
return self::_NAD;
case ISO3166TwoEnum::_NPL:
return self::_NPR;
case ISO3166TwoEnum::_NCL:
return self::_XPF;
case ISO3166TwoEnum::_NZL:
return self::_NZD;
case ISO3166TwoEnum::_NIC:
return self::_NIO;
case ISO3166TwoEnum::_NER:
return self::_XOF;
case ISO3166TwoEnum::_NGA:
return self::_NGN;
case ISO3166TwoEnum::_NFK:
return self::_AUD;
case ISO3166TwoEnum::_MNP:
return self::_USD;
case ISO3166TwoEnum::_NOR:
return self::_NOK;
case ISO3166TwoEnum::_OMN:
return self::_OMR;
case ISO3166TwoEnum::_PAK:
return self::_PKR;
case ISO3166TwoEnum::_PLW:
return self::_USD;
case ISO3166TwoEnum::_PAN:
return self::_PAB;
case ISO3166TwoEnum::_PNG:
return self::_PGK;
case ISO3166TwoEnum::_PRY:
return self::_PYG;
case ISO3166TwoEnum::_PER:
return self::_PEN;
case ISO3166TwoEnum::_PHL:
return self::_PHP;
case ISO3166TwoEnum::_POL:
return self::_PLN;
case ISO3166TwoEnum::_PRI:
return self::_USD;
case ISO3166TwoEnum::_QAT:
return self::_QAR;
case ISO3166TwoEnum::_REU:
return self::_EUR;
case ISO3166TwoEnum::_ROU:
return self::_ROL;
case ISO3166TwoEnum::_RUS:
return self::_RUB;
case ISO3166TwoEnum::_RWA:
return self::_RWF;
case ISO3166TwoEnum::_WSM:
return self::_WST;
case ISO3166TwoEnum::_SMR:
return self::_EUR;
case ISO3166TwoEnum::_STP:
return self::_STD;
case ISO3166TwoEnum::_SAU:
return self::_SAR;
case ISO3166TwoEnum::_SEN:
return self::_XOF;
case ISO3166TwoEnum::_SRB:
return self::_EUR;
case ISO3166TwoEnum::_SYC:
return self::_SCR;
case ISO3166TwoEnum::_SLE:
return self::_SLL;
case ISO3166TwoEnum::_SGP:
return self::_SGD;
case ISO3166TwoEnum::_SVK:
return self::_EUR;
case ISO3166TwoEnum::_SVN:
return self::_EUR;
case ISO3166TwoEnum::_SLB:
return self::_SBD;
case ISO3166TwoEnum::_ZAF:
return self::_ZAR;
case ISO3166TwoEnum::_LKA:
return self::_LKR;
case ISO3166TwoEnum::_BLM:
return self::_EUR;
case ISO3166TwoEnum::_KNA:
return self::_XCD;
case ISO3166TwoEnum::_VIR:
return self::_USD;
case ISO3166TwoEnum::_LCA:
return self::_XCD;
case ISO3166TwoEnum::_SXM:
return self::_USD;
case ISO3166TwoEnum::_VCT:
return self::_XCD;
case ISO3166TwoEnum::_SUR:
return self::_SRG;
case ISO3166TwoEnum::_SWZ:
return self::_SZL;
case ISO3166TwoEnum::_SWE:
return self::_SEK;
case ISO3166TwoEnum::_CHE:
return self::_CHF;
case ISO3166TwoEnum::_TWN:
return self::_TWD;
case ISO3166TwoEnum::_TJK:
return self::_TJS;
case ISO3166TwoEnum::_TZA:
return self::_TZS;
case ISO3166TwoEnum::_THA:
return self::_THB;
case ISO3166TwoEnum::_TGO:
return self::_XOF;
case ISO3166TwoEnum::_TON:
return self::_TOP;
case ISO3166TwoEnum::_TTO:
return self::_TTD;
case ISO3166TwoEnum::_TUN:
return self::_TND;
case ISO3166TwoEnum::_TUR:
return self::_TRY;
case ISO3166TwoEnum::_TKM:
return self::_TMT;
case ISO3166TwoEnum::_TCA:
return self::_USD;
case ISO3166TwoEnum::_TUV:
return self::_AUD;
case ISO3166TwoEnum::_UGA:
return self::_UGX;
case ISO3166TwoEnum::_UKR:
return self::_UAH;
case ISO3166TwoEnum::_ARE:
return self::_AED;
case ISO3166TwoEnum::_USA:
return self::_USD;
case ISO3166TwoEnum::_URY:
return self::_UYU;
case ISO3166TwoEnum::_UZB:
return self::_UZS;
case ISO3166TwoEnum::_VUT:
return self::_VUV;
case ISO3166TwoEnum::_VAT:
return self::_EUR;
case ISO3166TwoEnum::_VEN:
return self::_VEB;
case ISO3166TwoEnum::_VNM:
return self::_VND;
case ISO3166TwoEnum::_WLF:
return self::_XPF;
case ISO3166TwoEnum::_YEM:
return self::_YER;
case ISO3166TwoEnum::_ZMB:
return self::_ZMK;
case ISO3166TwoEnum::_ZWE:
return self::_ZWD;
default:
return '';
}
}
}

View File

@ -235,18 +235,19 @@ final class L11nManager
/**
* Print a percentage value
*
* @param Localization $l11n Localization
* @param float $percentage Percentage value to print
* @param null|string $format Format type to use
* @param Localization $l11n Localization
* @param float|FloatInt $percentage Percentage value to print
* @param null|string $format Format type to use
*
* @return string
*
* @since 1.0.0
*/
public function getPercentage(Localization $l11n, float $percentage, ?string $format = null) : string
public function getPercentage(Localization $l11n, float | FloatInt $percentage, ?string $format = null) : string
{
return \number_format(
$percentage, $l11n->getPrecision()[$format ?? 'medium'],
\is_float($percentage) ? $percentage : $percentage->value / (FloatInt::DIVISOR * 100),
$l11n->getPrecision()[$format ?? 'medium'],
$l11n->getDecimal(),
$l11n->getThousands()
) . '%';
@ -277,7 +278,7 @@ final class L11nManager
$symbol ??= $l11n->currency;
if (\is_float($currency)) {
$currency = (int) ($currency * \pow(10, Money::MAX_DECIMALS));
$currency = (int) ($currency * FloatInt::DIVISOR);
}
if ($divide > 1 && !empty($symbol)) {

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
namespace phpOMS\Localization\LanguageDetection;
/**
* Langauge detection class
* Language detection class
*
* @package phpOMS\Localization\LanguageDetection
* @license https://opensource.org/licenses/mit-license.html MIT

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
namespace phpOMS\Localization\LanguageDetection;
/**
* Langauge match result
* Language match result
*
* @package phpOMS\Localization\LanguageDetection
* @license https://opensource.org/licenses/mit-license.html MIT
@ -43,7 +43,7 @@ class LanguageResult implements \ArrayAccess, \IteratorAggregate, \JsonSerializa
/**
* Constructor.
*
* @param array $result Langauge match results
* @param array $result Language match results
*
* @since 1.0.0
*/

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
namespace phpOMS\Localization\LanguageDetection;
/**
* Langauge training class
* Language training class
*
* @package phpOMS\Localization\LanguageDetection
* @license https://opensource.org/licenses/mit-license.html MIT

View File

@ -32,6 +32,16 @@ class RegionEnum extends Enum
public const EURO = 'Euro';
public const OECD = 'OECD';
public const NATO = 'NATO';
public const SCHENGEN = 'Schengen';
public const P5 = 'P5';
public const G8 = 'G8';
public const NORTH_EUROPE = 'North-Europe';
public const SOUTH_EUROPE = 'South-Europe';
@ -93,4 +103,6 @@ class RegionEnum extends Enum
public const DOMESTIC = 'Domestic';
public const EXPORT = 'Export';
public const DACH = 'DACH';
}

View File

@ -196,6 +196,11 @@ final class Functions
return $a % $b;
}
public static function modFloat(float $a, float $b) : float
{
return $a - ((int) ($a / $b)) * $b;
}
/**
* Check if value is odd.
*

View File

@ -21,6 +21,9 @@ namespace phpOMS\Message\Mail;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Continue implementation of email sending and receiving
* https://github.com/Karaka-Management/phpOMS/issues/258
*/
class Imap implements MailBoxInterface
{

View File

@ -21,6 +21,9 @@ namespace phpOMS\Message\Mail;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Continue implementation of email sending and receiving
* https://github.com/Karaka-Management/phpOMS/issues/258
*/
class Pop3 implements MailBoxInterface
{

View File

@ -30,6 +30,10 @@ use phpOMS\Utils\StringUtils;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @performance The modules use the module name for identification in many places
* where the module id should be used for performance reasons
* https://github.com/Karaka-Management/Karaka/issues/159
*/
abstract class ModuleAbstract
{
@ -290,6 +294,39 @@ abstract class ModuleAbstract
];
}
/**
* Create standard model background process response.
*
* The response object contains the following data:
*
* * status = Response status
* * title = Response title (e.g. for frontend reporting)
* * message = Response message (e.g. for frontend reporting)
* * response = Response object (e.g. for validation/frontend reporting/form validation)
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $obj Response object
*
* @return void
*
* @since 1.0.0
*/
public function createStandardBackgroundResponse(
RequestAbstract $request,
ResponseAbstract $response,
mixed $obj
) : void
{
$response->header->set('Content-Type', MimeType::M_JSON . '; charset=utf-8', true);
$response->data[$request->uri->__toString()] = [
'status' => NotificationLevel::INFO,
'title' => '',
'message' => $this->app->l11nManager->getText($response->header->l11n->language, '0', '0', 'SuccessfulBackground'),
'response' => $obj,
];
}
/**
* Create standard model update response.
*

View File

@ -30,6 +30,14 @@ use phpOMS\Module\Exception\InvalidModuleException;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Implement a strategy for managing optional modules (e.g., comment module within the news module).
* Previously, modifications to the Mapper were made (e.g., comments were removed) when the comment module was installed.
* However, this approach is no longer viable. One potential solution is to introduce a separate Mapper
* that is dynamically replaced if the comment module is installed.
* Instead of replacing the entire file, a differential approach should be adopted, where only the ADDED lines are merged.
* Consideration must be given to uninstallation scenarios, as determining precisely what to remove is currently problematic.
* https://github.com/Karaka-Management/Karaka/issues/155
*/
final class ModuleManager
{
@ -253,7 +261,7 @@ final class ModuleManager
{
$name = '\\Modules\\' . $module . '\\Controller\\' . ($ctlName ?? $this->app->appName) . 'Controller';
return isset($this->running[$name]);
return isset($this->running[$module][$name]);
}
/**
@ -646,6 +654,41 @@ final class ModuleManager
$class::install($this->app, $this->modulePath);
}
/**
* Initialize module.
*
* Also registers controller in the dispatcher
*
* @param string $module Module
* @param string $ctlName Controller name (null = current app)
*
* @return void
*
* @since 1.0.0
*/
private function initModuleController(string $module, ?string $ctlName = null) : void
{
$name = '\\Modules\\' . $module . '\\Controller\\' . ($ctlName ?? $this->app->appName) . 'Controller';
$ctrl = $this->get($module, $ctlName);
if ($this->app->dispatcher !== null) {
$this->app->dispatcher->set($ctrl, $name);
}
// Handle providing->receiving
foreach ($this->running as $mName => $controllers) {
$controller = \reset($controllers);
foreach ($controller::$providing as $providing) {
$ctrl = \reset($this->running[$providing]);
if (!\in_array($mName, $ctrl->receiving)) {
$ctrl->receiving[] = $mName;
}
}
}
}
/**
* Get module instance.
*
@ -666,69 +709,31 @@ final class ModuleManager
* @since 1.0.0
*/
public function get(string $module, ?string $ctlName = null) : ModuleAbstract
{
$name = '\\Modules\\' . $module . '\\Controller\\' . ($ctlName ?? $this->app->appName) . 'Controller';
if (!isset($this->running[$name])) {
$this->initModuleController($module, $ctlName);
}
/* @phpstan-ignore-next-line */
return $this->running[$name] ?? new NullModule();
}
/**
* Initialize module.
*
* Also registers controller in the dispatcher
*
* @param string $module Module
* @param string $ctlName Controller name (null = current app)
*
* @return void
*
* @since 1.0.0
*/
private function initModuleController(string $module, ?string $ctlName = null) : void
{
$name = '\\Modules\\' . $module . '\\Controller\\' . ($ctlName ?? $this->app->appName) . 'Controller';
$this->running[$name] = $this->getModuleInstance($module, $ctlName);
if ($this->app->dispatcher !== null) {
$this->app->dispatcher->set($this->running[$name], $name);
}
}
/**
* Gets and initializes modules.
*
* @param string $module Module ID
* @param string $ctlName Controller name (null = current app)
*
* @return ModuleAbstract
*
* @since 1.0.0
*/
public function getModuleInstance(string $module, ?string $ctlName = null) : ModuleAbstract
{
$class = '\\Modules\\' . $module . '\\Controller\\' . ($ctlName ?? $this->app->appName) . 'Controller';
if (!isset($this->running[$class])) {
if (Autoloader::exists($class)
|| Autoloader::exists($class = '\\Modules\\' . $module . '\\Controller\\Controller')
) {
try {
/** @var ModuleAbstract $obj */
$obj = new $class($this->app);
$this->running[$class] = $obj;
} catch (\Throwable $_) {
$this->running[$class] = new NullModule();
}
} else {
$this->running[$class] = new NullModule();
}
if (!isset($this->running[$module])) {
$this->running[$module] = [];
}
return $this->running[$class];
if (isset($this->running[$module][$class])) {
return $this->running[$module][$class];
}
if (Autoloader::exists($class)
|| Autoloader::exists($class = '\\Modules\\' . $module . '\\Controller\\Controller')
) {
try {
/** @var ModuleAbstract $obj */
$obj = new $class($this->app);
$this->running[$module][$class] = $obj;
} catch (\Throwable $_) {
$this->running[$module][$class] = new NullModule();
}
} else {
$this->running[$module][$class] = new NullModule();
}
return $this->running[$module][$class];
}
/**

View File

@ -23,6 +23,13 @@ use phpOMS\Account\Account;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Change the url format in most modules from query parameter to path
* (e.g. `/module/profile?id=Admin` to `/module/Admin/profile`)
* https://github.com/Karaka-Management/Karaka/issues/153
*
* @todo Instead of doing only regex matching, combine it with a tree search, this should be faster
* https://github.com/Karaka-Management/phpOMS/issues/276
*/
final class WebRouter implements RouterInterface
{

View File

@ -26,6 +26,9 @@ use phpOMS\Socket\SocketAbstract;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Implement
* https://github.com/Karaka-Management/phpOMS/issues/277
*/
class Client extends SocketAbstract
{

View File

@ -27,6 +27,9 @@ use phpOMS\Socket\SocketAbstract;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Implement
* https://github.com/Karaka-Management/phpOMS/issues/278
*/
class Server extends SocketAbstract
{

View File

@ -34,6 +34,8 @@ class FloatInt implements SerializableInterface
*/
public const MAX_DECIMALS = 4;
public const DIVISOR = 10000;
/**
* Thousands separator.
*
@ -69,9 +71,9 @@ class FloatInt implements SerializableInterface
*/
public function __construct(int | float | string $value = 0, string $thousands = ',', string $decimal = '.')
{
$this->value = \is_int($value) ? $value : self::toInt((string) $value);
$this->thousands = $thousands;
$this->decimal = $decimal;
$this->value = \is_int($value) ? $value : self::toInt((string) $value, $thousands, $decimal);
}
/**
@ -89,26 +91,19 @@ class FloatInt implements SerializableInterface
*/
public static function toInt(string $value, string $thousands = ',', string $decimal = '.') : int
{
$split = \explode($decimal, $value);
$newValue = $value;
$len = \strlen($value);
if ($split === false) {
throw new \Exception('Internal explode error.'); // @codeCoverageIgnore
$decimalPos = \strrpos($value, $decimal);
if ($decimalPos === false) {
$decimalPos = $len - 1;
}
$left = $split[0];
$left = \str_replace($thousands, '', $left);
$right = '';
$newValue = \str_pad($newValue, 4 - (- $decimalPos - 1), '0');
$newValue = \str_replace([$thousands, $decimal], ['', ''], $newValue);
$newValue = \ltrim($newValue, '0');
if (\count($split) > 1) {
$right = $split[1];
}
$right = \substr($right, 0, self::MAX_DECIMALS);
if ($right === false) {
throw new \Exception('Internal substr error.'); // @codeCoverageIgnore
}
return ((int) $left) * 10 ** self::MAX_DECIMALS + (int) \str_pad($right, self::MAX_DECIMALS, '0');
return (int) $newValue;
}
/**
@ -147,12 +142,12 @@ class FloatInt implements SerializableInterface
public function getNormalizedValue() : float
{
return $this->value / \pow(10, self::MAX_DECIMALS);
return $this->value / self::DIVISOR;
}
public function guessScalarValue() : int|float
{
$divider = \pow(10, self::MAX_DECIMALS);
$divider = self::DIVISOR;
return $this->value % $divider === 0
? (int) ($this->value / $divider)
@ -206,17 +201,15 @@ class FloatInt implements SerializableInterface
*/
public function getFloat(?int $decimals = 2) : string
{
$isNegative = $this->value < 0 ? 1 : 0;
$value = $this->value === 0
? \str_repeat('0', self::MAX_DECIMALS)
: (string) \round($this->value, -self::MAX_DECIMALS + $decimals);
$left = \substr($value, 0, -self::MAX_DECIMALS + $isNegative);
$left = \substr($value, 0, -self::MAX_DECIMALS);
/** @var string $left */
$left = $left === false ? '0' : $left;
$right = \substr($value, -self::MAX_DECIMALS + $isNegative);
$right = \substr($value, -self::MAX_DECIMALS);
if ($right === false) {
throw new \Exception(); // @codeCoverageIgnore
@ -388,4 +381,29 @@ class FloatInt implements SerializableInterface
return $this;
}
public static function identifyNumericFormat(string $str) : ?array
{
$commaPos = \strrpos($str, ',');
$periodPos = \strrpos($str, '.');
if ($commaPos !== false && $periodPos !== false) {
return [
'thousands' => $commaPos < $periodPos ? ',' : '.',
'decimal' => $commaPos < $periodPos ? '.' : ',',
];
} elseif ($commaPos === false && $periodPos === false) {
return null;
}
// Back to normal cases
$isComma = $commaPos !== false
? $commaPos + 3 === \strlen($str)
: $periodPos + 3 !== \strlen($str);
return [
'thousands' => $isComma ? '.' : ',',
'decimal' => $isComma ? ',' : '.'
];
}
}

View File

@ -119,7 +119,7 @@ class Iban implements SerializableInterface
$country = $this->getCountry();
/** @var string $iban */
$iban = IbanEnum::getByName('C_' . $country);
$iban = IbanEnum::getByName('_' . $country);
$layout = \str_replace(' ', '', $iban);
$start = \stripos($layout, $sequence);
$end = \strrpos($layout, $sequence);

View File

@ -111,15 +111,18 @@ class SmartDateTime extends \DateTime
*/
public function smartModify(int $y = 0, int $m = 0, int $d = 0, int $calendar = \CAL_GREGORIAN) : self
{
$yearChange = (int) \floor(((int) $this->format('m') - 1 + $m) / 12);
$yearNew = (int) $this->format('Y') + $y + $yearChange;
$year = (int) $this->format('Y');
$month = (int) $this->format('m');
$monthNew = (int) $this->format('m') + $m;
$monthNew = $monthNew <= 0
? 12 + ($monthNew - 1) % 12 + 1
: ($monthNew - 1) % 12 + 1;
$yearChange = (int) \floor(($month - 1 + $m) / 12);
$yearNew = $year + $y + $yearChange;
$dayMonthOld = \cal_days_in_month($calendar, (int) $this->format('m'), (int) $this->format('Y'));
$monthNew = $month - 1 + $m;
$monthNew = $monthNew < 0
? ($month - 1 + $m - 12 * $yearChange) % 12 + 1
: $monthNew % 12 + 1;
$dayMonthOld = \cal_days_in_month($calendar, $month, $year);
$dayMonthNew = \cal_days_in_month($calendar, $monthNew, $yearNew);
$dayOld = (int) $this->format('d');

View File

@ -55,27 +55,27 @@ final class HtmlParser
);
$doc->loadHTMLFile($path);
$content = '';
if (empty($xpath)) {
$body = $doc->getElementsByTagName('body');
$node = $body->item(0);
$content = empty($node->textContent) ? '' : $node->textContent;
} else {
$xNode = new \DOMXpath($doc);
$elements = $xNode->query($xpath);
return empty($node->textContent) ? '' : $node->textContent;
}
if ($elements === false) {
return $content;
}
$content = '';
$xNode = new \DOMXpath($doc);
$elements = $xNode->query($xpath);
foreach ($elements as $element) {
$nodes = $element->childNodes;
if ($elements === false) {
return $content;
}
foreach ($nodes as $node) {
$content .= $node->textContent . "\n";
}
foreach ($elements as $element) {
$nodes = $element->childNodes;
foreach ($nodes as $node) {
$content .= $node->textContent . "\n";
}
}

View File

@ -144,6 +144,7 @@ final class PdfParser
foreach ($files as $file) {
if (!StringUtils::endsWith($file, '.jpg')
&& !StringUtils::endsWith($file, '.jpeg')
&& !StringUtils::endsWith($file, '.png')
&& !StringUtils::endsWith($file, '.gif')
) {

View File

@ -0,0 +1,83 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package phpOMS\Utils\Parser\Xml
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace phpOMS\Utils\Parser\Xml;
/**
* Xml parser class.
*
* @package phpOMS\Utils\Parser\Xml
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class XmlParser
{
/**
* Constructor.
*
* @since 1.0.0
* @codeCoverageIgnore
*/
private function __construct()
{
}
/**
* Xml to string
*
* @param string $path Path
*
* @return string
*
* @since 1.0.0
*/
public static function parseXml(string $path, string $output = 'xml', string $xpath = '') : string
{
$doc = new \DOMDocument();
$doc->preserveWhiteSpace = true;
$doc->formatOutput = true;
$xml = \file_get_contents($path);
$xml = \preg_replace(
['~<style.*?</style>~', '~<script.*?</script>~'],
['', ''],
$xml
);
$doc->loadXML($path);
if (empty($xpath)) {
return $doc->loadXML($xml);
}
$content = '';
$xNode = new \DOMXpath($doc);
$elements = $xNode->query($xpath);
if ($elements === false) {
return $content;
}
foreach ($elements as $element) {
$nodes = $element->childNodes;
foreach ($nodes as $node) {
$content .= $node->textContent . "\n";
}
}
return $content;
}
}

View File

@ -23,6 +23,9 @@ use phpOMS\Validation\Base\DateTime;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Use `Interval` for scheduler instead of string etc.
* https://github.com/Karaka-Management/phpOMS/issues/257
*/
class Schedule extends TaskAbstract
{

View File

@ -42,7 +42,7 @@ final class Iban extends ValidatorAbstract
return false; // @codeCoverageIgnore
}
$enumName = 'C_' . \strtoupper($temp);
$enumName = '_' . \strtoupper($temp);
if (!IbanEnum::isValidName($enumName)) {
self::$error = IbanErrorType::INVALID_COUNTRY;

View File

@ -26,167 +26,167 @@ use phpOMS\Stdlib\Base\Enum;
*/
class IbanEnum extends Enum
{
public const C_AL = 'ALkk bbbs sssx cccc cccc cccc cccc';
public const _AL = 'ALkk bbbs sssx cccc cccc cccc cccc';
public const C_AD = 'ADkk bbbb ssss cccc cccc cccc';
public const _AD = 'ADkk bbbb ssss cccc cccc cccc';
public const C_AT = 'ATkk bbbb bccc cccc cccc';
public const _AT = 'ATkk bbbb bccc cccc cccc';
public const C_AZ = 'AZkk bbbb cccc cccc cccc cccc cccc ';
public const _AZ = 'AZkk bbbb cccc cccc cccc cccc cccc ';
public const C_BH = 'BHkk bbbb cccc cccc cccc cc';
public const _BH = 'BHkk bbbb cccc cccc cccc cc';
public const C_BE = 'BEkk bbbc cccc ccxx';
public const _BE = 'BEkk bbbc cccc ccxx';
public const C_BA = 'BAkk bbbs sscc cccc ccxx';
public const _BA = 'BAkk bbbs sscc cccc ccxx';
public const C_BR = 'BRkk bbbb bbbb ssss sccc cccc ccct n';
public const _BR = 'BRkk bbbb bbbb ssss sccc cccc ccct n';
public const C_BG = 'BGkk bbbb ssss ttcc cccc cc';
public const _BG = 'BGkk bbbb ssss ttcc cccc cc';
public const C_CR = 'CRkk bbbc cccc cccc cccc c';
public const _CR = 'CRkk bbbc cccc cccc cccc c';
public const C_HR = 'HRkk bbbb bbbc cccc cccc c';
public const _HR = 'HRkk bbbb bbbc cccc cccc c';
public const C_CY = 'CYkk bbbs ssss cccc cccc cccc cccc';
public const _CY = 'CYkk bbbs ssss cccc cccc cccc cccc';
public const C_CZ = 'CZkk bbbb ssss sscc cccc cccc';
public const _CZ = 'CZkk bbbb ssss sscc cccc cccc';
public const C_DK = 'DKkk bbbb cccc cccc cc';
public const _DK = 'DKkk bbbb cccc cccc cc';
public const C_DO = 'DOkk bbbb cccc cccc cccc cccc cccc';
public const _DO = 'DOkk bbbb cccc cccc cccc cccc cccc';
public const C_TL = 'TLkk bbbc cccc cccc cccc cxx';
public const _TL = 'TLkk bbbc cccc cccc cccc cxx';
public const C_EE = 'EEkk bbss cccc cccc cccx';
public const _EE = 'EEkk bbss cccc cccc cccx';
public const C_FO = 'FOkk bbbb cccc cccc cx';
public const _FO = 'FOkk bbbb cccc cccc cx';
public const C_FI = 'FIkk bbbb bbcc cccc cx';
public const _FI = 'FIkk bbbb bbcc cccc cx';
public const C_FR = 'FRkk bbbb bsss sscc cccc cccc cxx';
public const _FR = 'FRkk bbbb bsss sscc cccc cccc cxx';
public const C_GE = 'GEkk bbcc cccc cccc cccc cc';
public const _GE = 'GEkk bbcc cccc cccc cccc cc';
public const C_DE = 'DEkk bbbb bbbb cccc cccc cc';
public const _DE = 'DEkk bbbb bbbb cccc cccc cc';
public const C_GI = 'GIkk bbbb cccc cccc cccc ccc';
public const _GI = 'GIkk bbbb cccc cccc cccc ccc';
public const C_GR = 'GRkk bbbs sssc cccc cccc cccc ccc';
public const _GR = 'GRkk bbbs sssc cccc cccc cccc ccc';
public const C_GL = 'GLkk bbbb cccc cccc cc';
public const _GL = 'GLkk bbbb cccc cccc cc';
public const C_GT = 'GTkk bbbb mmtt cccc cccc cccc cccc';
public const _GT = 'GTkk bbbb mmtt cccc cccc cccc cccc';
public const C_HU = 'HUkk bbbs sssx cccc cccc cccc cccx';
public const _HU = 'HUkk bbbs sssx cccc cccc cccc cccx';
public const C_IS = 'ISkk bbbb sscc cccc iiii iiii ii';
public const _IS = 'ISkk bbbb sscc cccc iiii iiii ii';
public const C_IE = 'IEkk aaaa bbbb bbcc cccc cc';
public const _IE = 'IEkk aaaa bbbb bbcc cccc cc';
public const C_IL = 'ILkk bbbn nncc cccc cccc ccc';
public const _IL = 'ILkk bbbn nncc cccc cccc ccc';
public const C_IT = 'ITkk xbbb bbss sssc cccc cccc ccc';
public const _IT = 'ITkk xbbb bbss sssc cccc cccc ccc';
public const C_JO = 'JOkk bbbb ssss cccc cccc cccc cccc cc';
public const _JO = 'JOkk bbbb ssss cccc cccc cccc cccc cc';
public const C_KZ = 'KZkk bbbc cccc cccc cccc';
public const _KZ = 'KZkk bbbc cccc cccc cccc';
public const C_XK = 'XKkk bbbb cccc cccc cccc';
public const _XK = 'XKkk bbbb cccc cccc cccc';
public const C_KW = 'KWkk bbbb cccc cccc cccc cccc cccc cc';
public const _KW = 'KWkk bbbb cccc cccc cccc cccc cccc cc';
public const C_LV = 'LVkk bbbb cccc cccc cccc c';
public const _LV = 'LVkk bbbb cccc cccc cccc c';
public const C_LB = 'LBkk bbbb cccc cccc cccc cccc cccc';
public const _LB = 'LBkk bbbb cccc cccc cccc cccc cccc';
public const C_LI = 'LIkk bbbb bccc cccc cccc c';
public const _LI = 'LIkk bbbb bccc cccc cccc c';
public const C_LT = 'LTkk bbbb bccc cccc cccc';
public const _LT = 'LTkk bbbb bccc cccc cccc';
public const C_LU = 'LUkk bbbc cccc cccc cccc';
public const _LU = 'LUkk bbbc cccc cccc cccc';
public const C_MK = 'MKkk bbbc cccc cccc cxx';
public const _MK = 'MKkk bbbc cccc cccc cxx';
public const C_MT = 'MTkk bbbb ssss sccc cccc cccc cccc ccc';
public const _MT = 'MTkk bbbb ssss sccc cccc cccc cccc ccc';
public const C_MR = 'MRkk bbbb bsss sscc cccc cccc cxx';
public const _MR = 'MRkk bbbb bsss sscc cccc cccc cxx';
public const C_MU = 'MUkk bbbb bbss cccc cccc cccc 000m mm';
public const _MU = 'MUkk bbbb bbss cccc cccc cccc 000m mm';
public const C_MC = 'MCkk bbbb bsss sscc cccc cccc cxx';
public const _MC = 'MCkk bbbb bsss sscc cccc cccc cxx';
public const C_MD = 'MDkk bbcc cccc cccc cccc cccc';
public const _MD = 'MDkk bbcc cccc cccc cccc cccc';
public const C_ME = 'MEkk bbbc cccc cccc cccc xx';
public const _ME = 'MEkk bbbc cccc cccc cccc xx';
public const C_NL = 'NLkk bbbb cccc cccc cc';
public const _NL = 'NLkk bbbb cccc cccc cc';
public const C_NO = 'NOkk bbbb cccc ccx';
public const _NO = 'NOkk bbbb cccc ccx';
public const C_PK = 'PKkk bbbb cccc cccc cccc cccc';
public const _PK = 'PKkk bbbb cccc cccc cccc cccc';
public const C_PS = 'PSkk bbbb xxxx xxxx xccc cccc cccc c';
public const _PS = 'PSkk bbbb xxxx xxxx xccc cccc cccc c';
public const C_PL = 'PLkk bbbs sssx cccc cccc cccc cccc';
public const _PL = 'PLkk bbbs sssx cccc cccc cccc cccc';
public const C_PT = 'PTkk bbbb ssss cccc cccc cccx x';
public const _PT = 'PTkk bbbb ssss cccc cccc cccx x';
public const C_QA = 'QAkk bbbb cccc cccc cccc cccc cccc c';
public const _QA = 'QAkk bbbb cccc cccc cccc cccc cccc c';
public const C_RO = 'ROkk bbbb cccc cccc cccc cccc';
public const _RO = 'ROkk bbbb cccc cccc cccc cccc';
public const C_SM = 'SMkk xbbb bbss sssc cccc cccc ccc';
public const _SM = 'SMkk xbbb bbss sssc cccc cccc ccc';
public const C_SA = 'SAkk bbcc cccc cccc cccc cccc';
public const _SA = 'SAkk bbcc cccc cccc cccc cccc';
public const C_RS = 'RSkk bbbc cccc cccc cccc xx';
public const _RS = 'RSkk bbbc cccc cccc cccc xx';
public const C_SK = 'SKkk bbbb ssss sscc cccc cccc';
public const _SK = 'SKkk bbbb ssss sscc cccc cccc';
public const C_SI = 'SIkk bbss sccc cccc cxx';
public const _SI = 'SIkk bbss sccc cccc cxx';
public const C_ES = 'ESkk bbbb ssss xxcc cccc cccc';
public const _ES = 'ESkk bbbb ssss xxcc cccc cccc';
public const C_SE = 'SEkk bbbc cccc cccc cccc cccc';
public const _SE = 'SEkk bbbc cccc cccc cccc cccc';
public const C_CH = 'CHkk bbbb bccc cccc cccc c';
public const _CH = 'CHkk bbbb bccc cccc cccc c';
public const C_TN = 'TNkk bbss sccc cccc cccc cccc';
public const _TN = 'TNkk bbss sccc cccc cccc cccc';
public const C_TR = 'TRkk bbbb bxcc cccc cccc cccc cc';
public const _TR = 'TRkk bbbb bxcc cccc cccc cccc cc';
public const C_UA = 'UAkk bbbb bbcc cccc cccc cccc cccc c';
public const _UA = 'UAkk bbbb bbcc cccc cccc cccc cccc c';
public const C_AE = 'AEkk bbbc cccc cccc cccc ccc';
public const _AE = 'AEkk bbbc cccc cccc cccc ccc';
public const C_GB = 'GBkk bbbb ssss sscc cccc cc';
public const _GB = 'GBkk bbbb ssss sscc cccc cc';
public const C_VG = 'VGkk bbbb cccc cccc cccc cccc';
public const _VG = 'VGkk bbbb cccc cccc cccc cccc';
public const C_SN = 'SNkk annn nnnn nnnn nnnn nnnn nnnn';
public const _SN = 'SNkk annn nnnn nnnn nnnn nnnn nnnn';
public const C_MZ = 'MZkk nnnn nnnn nnnn nnnn nnnn n';
public const _MZ = 'MZkk nnnn nnnn nnnn nnnn nnnn n';
public const C_ML = 'MLkk annn nnnn nnnn nnnn nnnn nnnn';
public const _ML = 'MLkk annn nnnn nnnn nnnn nnnn nnnn';
public const C_MG = 'MGkk nnnn nnnn nnnn nnnn nnnn nnn';
public const _MG = 'MGkk nnnn nnnn nnnn nnnn nnnn nnn';
public const C_CI = 'CIkk annn nnnn nnnn nnnn nnnn nnnn';
public const _CI = 'CIkk annn nnnn nnnn nnnn nnnn nnnn';
public const C_IR = 'IRkk nnnn nnnn nnnn nnnn nnnn nn';
public const _IR = 'IRkk nnnn nnnn nnnn nnnn nnnn nn';
public const C_CV = 'CVkk nnnn nnnn nnnn nnnn nnnn n';
public const _CV = 'CVkk nnnn nnnn nnnn nnnn nnnn n';
public const C_CM = 'CMkk nnnn nnnn nnnn nnnn nnnn nnn';
public const _CM = 'CMkk nnnn nnnn nnnn nnnn nnnn nnn';
public const C_BI = 'BIkk nnnn nnnn nnnn';
public const _BI = 'BIkk nnnn nnnn nnnn';
public const C_BF = 'BFkk nnnn nnnn nnnn nnnn nnnn nnn';
public const _BF = 'BFkk nnnn nnnn nnnn nnnn nnnn nnn';
public const C_BJ = 'BJkk annn nnnn nnnn nnnn nnnn nnnn';
public const _BJ = 'BJkk annn nnnn nnnn nnnn nnnn nnnn';
public const C_AO = 'AOkk nnnn nnnn nnnn nnnn nnnn n';
public const _AO = 'AOkk nnnn nnnn nnnn nnnn nnnn n';
public const C_DZ = 'DZkk nnnn nnnn nnnn nnnn nnnn';
public const _DZ = 'DZkk nnnn nnnn nnnn nnnn nnnn';
}

View File

@ -325,14 +325,14 @@ class View extends ViewAbstract
/**
* Print a percentage value
*
* @param float $percentage Percentage value to print
* @param null|string $format Format type to use
* @param float|FloatInt $percentage Percentage value to print
* @param null|string $format Format type to use
*
* @return string
*
* @since 1.0.0
*/
public function getPercentage(float $percentage, ?string $format = null) : string
public function getPercentage(float | FloatInt $percentage, ?string $format = null) : string
{
return $this->l11nManager->getPercentage($this->l11n, $percentage, $format);
}

View File

@ -32,7 +32,7 @@ abstract class ViewAbstract implements RenderableInterface
* @var string
* @since 1.0.0
*/
protected const BASE_PATH = __DIR__ . '/../..';
public const BASE_PATH = __DIR__ . '/../..';
/**
* Output is buffered
@ -230,7 +230,7 @@ abstract class ViewAbstract implements RenderableInterface
}
/**
* Arrayify view and it's subviews.
* Arrayify view and it's sub-views.
*
* @return array
*

View File

@ -1,32 +0,0 @@
<?php
/**
* Jingga
*
* 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\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Query\Column;
/**
* @internal
*/
final class ColumnTest extends \PHPUnit\Framework\TestCase
{
/**
* @covers phpOMS\DataStorage\Database\Query\Column
* @group framework
*/
public function testDefault() : void
{
self::assertInstanceOf('\phpOMS\DataStorage\Database\Query\Builder', new Column($GLOBALS['dbpool']->get()));
}
}

View File

@ -1,32 +0,0 @@
<?php
/**
* Jingga
*
* 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\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Query\Count;
/**
* @internal
*/
final class CountTest extends \PHPUnit\Framework\TestCase
{
/**
* @covers phpOMS\DataStorage\Database\Query\Count
* @group framework
*/
public function testDefault() : void
{
self::assertInstanceOf('\phpOMS\DataStorage\Database\Query\Builder', new Count($GLOBALS['dbpool']->get()));
}
}

View File

@ -1,32 +0,0 @@
<?php
/**
* Jingga
*
* 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\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Query\Expression;
/**
* @internal
*/
final class ExpressionTest extends \PHPUnit\Framework\TestCase
{
/**
* @covers phpOMS\DataStorage\Database\Query\Expression
* @group framework
*/
public function testDefault() : void
{
self::assertInstanceOf('\phpOMS\DataStorage\Database\Query\Builder', new Expression($GLOBALS['dbpool']->get()));
}
}

View File

@ -1,32 +0,0 @@
<?php
/**
* Jingga
*
* 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\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Query\From;
/**
* @internal
*/
final class FromTest extends \PHPUnit\Framework\TestCase
{
/**
* @covers phpOMS\DataStorage\Database\Query\From
* @group framework
*/
public function testDefault() : void
{
self::assertInstanceOf('\phpOMS\DataStorage\Database\Query\Builder', new From($GLOBALS['dbpool']->get()));
}
}

View File

@ -1,32 +0,0 @@
<?php
/**
* Jingga
*
* 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\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Query\Into;
/**
* @internal
*/
final class IntoTest extends \PHPUnit\Framework\TestCase
{
/**
* @covers phpOMS\DataStorage\Database\Query\Into
* @group framework
*/
public function testDefault() : void
{
self::assertInstanceOf('\phpOMS\DataStorage\Database\Query\Builder', new Into($GLOBALS['dbpool']->get()));
}
}

View File

@ -1,32 +0,0 @@
<?php
/**
* Jingga
*
* 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\DataStorage\Database\Query;
use phpOMS\DataStorage\Database\Query\Select;
/**
* @internal
*/
final class SelectTest extends \PHPUnit\Framework\TestCase
{
/**
* @covers phpOMS\DataStorage\Database\Query\Select
* @group framework
*/
public function testDefault() : void
{
self::assertInstanceOf('\phpOMS\DataStorage\Database\Query\Builder', new Select($GLOBALS['dbpool']->get()));
}
}

View File

@ -53,7 +53,7 @@ final class WebRouterTest extends \PHPUnit\Framework\TestCase
{
self::assertEmpty(
$this->router->route(
(new HttpRequest(new HttpUri('')))->uri->getRoute()
(new HttpRequest())->uri->getRoute()
)
);
}

View File

@ -251,7 +251,7 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
*/
public function testGetRequest() : void
{
$view = new View($this->app->l11nManager, $request = new HttpRequest(new HttpUri('')), $response = new HttpResponse());
$view = new View($this->app->l11nManager, $request = new HttpRequest(), $response = new HttpResponse());
self::assertEquals($request, $view->request);
self::assertEquals($response, $view->response);
@ -264,7 +264,7 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
*/
public function testGetResponse() : void
{
$view = new View($this->app->l11nManager, new HttpRequest(new HttpUri('')), $response = new HttpResponse());
$view = new View($this->app->l11nManager, new HttpRequest(), $response = new HttpResponse());
self::assertEquals($response, $view->response);
}
@ -276,7 +276,7 @@ final class ViewTest extends \PHPUnit\Framework\TestCase
*/
public function testPrintHtml() : void
{
$view = new View($this->app->l11nManager, $request = new HttpRequest(new HttpUri('')), $response = new HttpResponse());
$view = new View($this->app->l11nManager, $request = new HttpRequest(), $response = new HttpResponse());
self::assertEquals('&lt;a href=&quot;test&quot;&gt;Test&lt;/a&gt;', $view->printHtml('<a href="test">Test</a>'));
self::assertEquals('&lt;a href=&quot;test&quot;&gt;Test&lt;/a&gt;', ViewAbstract::html('<a href="test">Test</a>'));