Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Dennis Eichhorn 2018-08-24 12:09:50 +02:00
commit feb652a026
157 changed files with 3136 additions and 1363 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
*.log *.log
.directory
vendor

23
.travis.yml Normal file
View File

@ -0,0 +1,23 @@
language: php
php:
- '7.2'
- nightly
services:
- mysql
before_script:
- pecl install ast
- composer install
- git clone -b develop https://github.com/Orange-Management/Build.git
- chmod -R 755 Build/Hooks
addons:
code_climate:
repo_token:
secure: "zXoveZL6QPXXcdyGxfgjlIRGSFbTgwi2NU6V9tROypLMA+5IWRd0CvvQkl4vx2lIAF5Pn3jOGqG6p6qinqwSzX2tE/RsdDEDz8LPKpN+AShyxLzzYu2ohDSqm3rSXysdgbjQBB1YoUIumhUGABfYIdZk+7g1Yjc3RLFdAs3YzB7CdG4zeBA1Xe82KHUDwZb2M/MG/Bf9jsi9HmjrBeMTmCiW8v6wclYG9rbkIoXY4mv4H0ywiTv4lHuyRWs19kJn4kKI3oLqmv0UcUmLv0wNgPrww2STtN/7ghlaiLNSrdKQV1EuVi/nRxxNlH2z+h8cMPAcksqZ29TT9RYkK32433QIUHYzN6t4LB8PgNkFPMc6zI6uzD9We4oYAw4bVIxkEgHXJBInfYSNRfoGPGHZ9WU+Ph9zt2nyB4mS6014gHgjBZSF+DV/r1mHa9XtXPDzxrbHJF7rIp99iOBnpGBcn4ERVhLP6onuam86TSgXjgyUrnTGazwKoc6cfwvb9RswpVtTvNJIYgzfJG6+QFAsltOSo3iRvKq+F2X3Lh/3dOAAcqh3TOZaSPee2sHCDFYq5d0qpNFJq/o6tEcPP9J6PmKsD7Ql9Zu1qNJ2MevheE/U/3sh2dy/5rhDSFCig2TRMy/53QATcCm2ngIfBJkeVyLQ2VMUsMXOk5v2uF16E6k="
script:
- vendor/bin/phpunit --version && vendor/bin/phpunit --configuration tests/phpunit_no_coverage.xml
- pwd
- ./Build/Hooks/travis.sh
after_script:
- vendor/bin/test-reporter
notifications:
email: false

View File

@ -453,11 +453,11 @@ class Account implements ArrayableInterface, \JsonSerializable
*/ */
public function setEmail(string $email) : void public function setEmail(string $email) : void
{ {
if (!Email::isValid($email)) { if ($email !== '' && !Email::isValid($email)) {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
$this->email = mb_strtolower($email); $this->email = \mb_strtolower($email);
} }
/** /**
@ -561,11 +561,13 @@ class Account implements ArrayableInterface, \JsonSerializable
*/ */
public function generatePassword(string $password) : void public function generatePassword(string $password) : void
{ {
$this->password = \password_hash($password, \PASSWORD_DEFAULT); $temp = \password_hash($password, \PASSWORD_DEFAULT);
if ($this->password === false) { if ($temp === false) {
throw new \Exception(); throw new \Exception();
} }
$this->password = $temp;
} }
/** /**
@ -603,7 +605,7 @@ class Account implements ArrayableInterface, \JsonSerializable
*/ */
public function __toString() : string public function __toString() : string
{ {
return \json_encode($this->toArray()); return (string) \json_encode($this->toArray());
} }
/** /**

View File

@ -189,7 +189,7 @@ class Group implements ArrayableInterface, \JsonSerializable
*/ */
public function __toString() : string public function __toString() : string
{ {
return \json_encode($this->toArray()); return (string) \json_encode($this->toArray());
} }
/** /**

View File

@ -22,6 +22,7 @@ namespace phpOMS;
* and afterwards read only. * and afterwards read only.
* *
* @property string $appName * @property string $appName
* @property int $orgId
* @property \phpOMS\DataStorage\Database\DatabasePool $dbPool * @property \phpOMS\DataStorage\Database\DatabasePool $dbPool
* @property \phpOMS\Localization\L11nManager $l11nManager * @property \phpOMS\Localization\L11nManager $l11nManager
* @property \phpOMS\Router\Router $router * @property \phpOMS\Router\Router $router
@ -50,6 +51,14 @@ class ApplicationAbstract
*/ */
protected $appName = ''; protected $appName = '';
/**
* Organization id.
*
* @var int
* @since 1.0.0
*/
protected $orgId = 1;
/** /**
* Database object. * Database object.
* *

View File

@ -81,7 +81,7 @@ final class Autoloader
$class = \str_replace(['_', '\\'], '/', $class); $class = \str_replace(['_', '\\'], '/', $class);
foreach (self::$paths as $path) { foreach (self::$paths as $path) {
if (file_exists($file = $path . $class . '.php')) { if (\file_exists($file = $path . $class . '.php')) {
include_once $file; include_once $file;
return; return;
@ -106,7 +106,7 @@ final class Autoloader
$class = \str_replace(['_', '\\'], '/', $class); $class = \str_replace(['_', '\\'], '/', $class);
foreach (self::$paths as $path) { foreach (self::$paths as $path) {
if (file_exists($file = $path . $class . '.php')) { if (\file_exists($file = $path . $class . '.php')) {
return true; return true;
} }
} }

View File

@ -48,7 +48,7 @@ final class FinanceFormulas
*/ */
public static function getAnnualPercentageYield(float $r, int $n) : float public static function getAnnualPercentageYield(float $r, int $n) : float
{ {
return (float) pow(1 + $r / $n, $n) - 1; return pow(1 + $r / $n, $n) - 1;
} }
/** /**
@ -65,7 +65,7 @@ final class FinanceFormulas
*/ */
public static function getStateAnnualInterestRateOfAPY(float $apy, int $n) : float public static function getStateAnnualInterestRateOfAPY(float $apy, int $n) : float
{ {
return (float) (pow($apy + 1, 1 / $n) - 1) * $n; return (pow($apy + 1, 1 / $n) - 1) * $n;
} }
/** /**
@ -922,7 +922,7 @@ final class FinanceFormulas
*/ */
public static function getFutureValueFactor(float $r, int $n) : float public static function getFutureValueFactor(float $r, int $n) : float
{ {
return (float) pow(1 + $r, $n); return pow(1 + $r, $n);
} }
/** /**

View File

@ -369,6 +369,6 @@ final class StockBonds
*/ */
public static function getZeroCouponBondEffectiveYield(float $F, float $PV, int $n) : float public static function getZeroCouponBondEffectiveYield(float $F, float $PV, int $n) : float
{ {
return (float) pow($F / $PV, 1 / $n) - 1; return pow($F / $PV, 1 / $n) - 1;
} }
} }

View File

@ -105,6 +105,11 @@ abstract class SettingsAbstract implements OptionsInterface
$sth->execute(); $sth->execute();
$options = $sth->fetchAll(\PDO::FETCH_KEY_PAIR); $options = $sth->fetchAll(\PDO::FETCH_KEY_PAIR);
if ($options === false) {
return [];
}
$this->setOptions($options); $this->setOptions($options);
break; break;
} }

View File

@ -1,129 +0,0 @@
<?php
/**
* Orange Management
*
* PHP Version 7.2
*
* @package TBD
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link http://website.orange-management.de
*/
declare(strict_types=1);
namespace phpOMS\Console;
/**
* CommandManager class.
*
* @package Framework
* @since 1.0.0
*
* @todo : Hey, this looks like a copy of an event manager!
*/
class CommandManager implements \Countable
{
/**
* Commands.
*
* @var mixed[]
* @since 1.0.0
*/
private $commands = [];
/**
* Commands.
*
* @var int
* @since 1.0.0
*/
private $count = 0;
/**
* Constructor.
*
* @since 1.0.0
*/
public function __construct()
{
}
/**
* Attach new command.
*
* @param string $cmd Command ID
* @param mixed $callback Function callback
* @param mixed $source Provider
* @param bool $overwrite Overwrite existing
*
* @return bool
*
* @since 1.0.0
*/
public function attach(string $cmd, $callback, $source, bool $overwrite = true) : bool
{
if ($overwrite || !isset($this->commands[$cmd])) {
$this->commands[$cmd] = [$callback, $source];
$this->count++;
return true;
}
return false;
}
/**
* Detach existing command.
*
* @param string $cmd Command ID
* @param mixed $source Provider
*
* @return bool
*
* @since 1.0.0
*/
public function detach(string $cmd, $source) : bool
{
if (array_key_exists($cmd, $this->commands)) {
unset($this->commands[$cmd]);
$this->count--;
return true;
}
return false;
}
/**
* Trigger command.
*
* @param string $cmd Command ID
* @param mixed $para Parameters to pass
*
* @return mixed|bool
*
* @since 1.0.0
*/
public function trigger(string $cmd, $para)
{
if (array_key_exists($cmd, $this->commands)) {
return $this->commands[$cmd][0]($para);
}
return false;
}
/**
* Count commands.
*
* @return int
*
* @since 1.0.0
*/
public function count() : int
{
return $this->count;
}
}

View File

@ -15,6 +15,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Cache\Connection; namespace phpOMS\DataStorage\Cache\Connection;
use phpOMS\DataStorage\Cache\CacheStatus; use phpOMS\DataStorage\Cache\CacheStatus;
use phpOMS\DataStorage\Cache\CacheType;
/** /**
* Cache handler. * Cache handler.
@ -38,7 +39,7 @@ abstract class ConnectionAbstract implements ConnectionInterface
* @var mixed * @var mixed
* @since 1.0.0 * @since 1.0.0
*/ */
private $con = null; protected $con = null;
/** /**
* Database prefix. * Database prefix.
@ -64,7 +65,7 @@ abstract class ConnectionAbstract implements ConnectionInterface
* @var string * @var string
* @since 1.0.0 * @since 1.0.0
*/ */
protected $type = CacheStatus::UNDEFINED; protected $type = CacheType::UNDEFINED;
/** /**
* Database status. * Database status.

View File

@ -218,7 +218,7 @@ class FileCache extends ConnectionAbstract
if ($type === CacheValueType::_INT || $type === CacheValueType::_FLOAT || $type === CacheValueType::_STRING || $type === CacheValueType::_BOOL) { if ($type === CacheValueType::_INT || $type === CacheValueType::_FLOAT || $type === CacheValueType::_STRING || $type === CacheValueType::_BOOL) {
return (string) $value; return (string) $value;
} elseif ($type === CacheValueType::_ARRAY) { } elseif ($type === CacheValueType::_ARRAY) {
return \json_encode($value); return (string) \json_encode($value);
} elseif ($type === CacheValueType::_SERIALIZABLE) { } elseif ($type === CacheValueType::_SERIALIZABLE) {
return \get_class($value) . self::DELIM . $value->serialize(); return \get_class($value) . self::DELIM . $value->serialize();
} elseif ($type === CacheValueType::_JSONSERIALIZABLE) { } elseif ($type === CacheValueType::_JSONSERIALIZABLE) {
@ -241,8 +241,8 @@ class FileCache extends ConnectionAbstract
*/ */
private function getExpire(string $raw) : int private function getExpire(string $raw) : int
{ {
$expireStart = \strpos($raw, self::DELIM); $expireStart = (int) \strpos($raw, self::DELIM);
$expireEnd = \strpos($raw, self::DELIM, $expireStart + 1); $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
return (int) \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); return (int) \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
} }
@ -257,7 +257,6 @@ class FileCache extends ConnectionAbstract
} }
$path = $this->getPath($key); $path = $this->getPath($key);
if (!File::exists($path)) { if (!File::exists($path)) {
return null; return null;
} }
@ -269,12 +268,21 @@ class FileCache extends ConnectionAbstract
return null; return null;
} }
$raw = File::get($path); $raw = \file_get_contents($path);
$type = (int) $raw[0]; if ($raw === false) {
return null;
}
$type = (int) $raw[0];
$expireStart = (int) \strpos($raw, self::DELIM);
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) {
return null;
}
$expireStart = \strpos($raw, self::DELIM);
$expireEnd = \strpos($raw, self::DELIM, $expireStart + 1);
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
$cacheExpire = ($cacheExpire === false) ? $created : (int) $cacheExpire;
if ($cacheExpire >= 0 && $created + $cacheExpire < $now) { if ($cacheExpire >= 0 && $created + $cacheExpire < $now) {
$this->delete($key); $this->delete($key);
@ -314,18 +322,23 @@ class FileCache extends ConnectionAbstract
$value = \substr($raw, $expireEnd + 1); $value = \substr($raw, $expireEnd + 1);
break; break;
case CacheValueType::_ARRAY: case CacheValueType::_ARRAY:
$value = \json_decode(substr($raw, $expireEnd + 1)); $array = \substr($raw, $expireEnd + 1);
$value = \json_decode($array === false ? '[]' : $array, true);
break; break;
case CacheValueType::_NULL: case CacheValueType::_NULL:
$value = null; $value = null;
break; break;
case CacheValueType::_SERIALIZABLE: case CacheValueType::_SERIALIZABLE:
case CacheValueType::_JSONSERIALIZABLE: case CacheValueType::_JSONSERIALIZABLE:
$namespaceStart = \strpos($raw, self::DELIM, $expireEnd); $namespaceStart = (int) \strpos($raw, self::DELIM, $expireEnd);
$namespaceEnd = \strpos($raw, self::DELIM, $namespaceStart + 1); $namespaceEnd = (int) \strpos($raw, self::DELIM, $namespaceStart + 1);
$namespace = \substr($raw, $namespaceStart, $namespaceEnd); $namespace = \substr($raw, $namespaceStart, $namespaceEnd);
$value = $namespace::unserialize(substr($raw, $namespaceEnd + 1)); if ($namespace === false) {
return null;
}
$value = $namespace::unserialize(\substr($raw, $namespaceEnd + 1));
break; break;
} }
@ -342,7 +355,6 @@ class FileCache extends ConnectionAbstract
} }
$path = $this->getPath($key); $path = $this->getPath($key);
if ($expire < 0 && File::exists($path)) { if ($expire < 0 && File::exists($path)) {
File::delete($path); File::delete($path);
@ -350,12 +362,29 @@ class FileCache extends ConnectionAbstract
} }
if ($expire >= 0) { if ($expire >= 0) {
$created = Directory::created(Directory::sanitize($key, self::SANITIZE))->getTimestamp(); $created = Directory::created(Directory::sanitize($key, self::SANITIZE))->getTimestamp();
$now = \time(); $now = \time();
$raw = \file_get_contents($path); $raw = \file_get_contents($path);
$expireStart = \strpos($raw, self::DELIM);
$expireEnd = \strpos($raw, self::DELIM, $expireStart + 1); if ($raw === false) {
return false;
}
$expireStart = (int) \strpos($raw, self::DELIM);
$expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
if ($expireStart < 0 || $expireEnd < 0) {
return false;
}
$cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1)); $cacheExpire = \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
$cacheExpire = ($cacheExpire === false) ? $created : (int) $cacheExpire;
if ($cacheExpire >= 0 && $created + $cacheExpire < $now) {
$this->delete($key);
return false;
}
if ($cacheExpire >= 0 && $created + $cacheExpire > $now) { if ($cacheExpire >= 0 && $created + $cacheExpire > $now) {
File::delete($path); File::delete($path);

View File

@ -25,6 +25,15 @@ namespace phpOMS\DataStorage;
interface DataStorageConnectionInterface interface DataStorageConnectionInterface
{ {
/**
* Get prefix.
*
* @return string
*
* @since 1.0.0
*/
public function getPrefix() : string;
/** /**
* Connect to datastorage. * Connect to datastorage.
* *

View File

@ -44,7 +44,7 @@ interface DataStoragePoolInterface
* *
* @param string $key Connection key * @param string $key Connection key
* *
* @return mixed * @return DataStorageConnectionInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database; namespace phpOMS\DataStorage\Database;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract; use phpOMS\DataStorage\DataStorageConnectionInterface;
use phpOMS\DataStorage\Database\Query\QueryType; use phpOMS\DataStorage\Database\Query\QueryType;
/** /**
@ -38,7 +38,7 @@ abstract class BuilderAbstract
/** /**
* Database connection. * Database connection.
* *
* @var ConnectionAbstract * @var DataStorageConnectionInterface
* @since 1.0.0 * @since 1.0.0
*/ */
protected $connection = null; protected $connection = null;
@ -49,7 +49,7 @@ abstract class BuilderAbstract
* @var int * @var int
* @since 1.0.0 * @since 1.0.0
*/ */
protected $type = QueryType::EMPTY; protected $type = QueryType::NONE;
/** /**
* Prefix. * Prefix.
@ -68,15 +68,9 @@ abstract class BuilderAbstract
public $raw = ''; public $raw = '';
/** /**
* Set prefix. * {@inheritdoc}
*
* @param string $prefix Prefix
*
* @return BuilderAbstract
*
* @since 1.0.0
*/ */
public function prefix(string $prefix) : BuilderAbstract public function prefix(string $prefix) : self
{ {
$this->prefix = $prefix; $this->prefix = $prefix;

View File

@ -44,13 +44,13 @@ final class ConnectionFactory
* *
* @param string[] $dbdata the basic database information for establishing a connection * @param string[] $dbdata the basic database information for establishing a connection
* *
* @return ConnectionInterface * @return ConnectionAbstract
* *
* @throws \InvalidArgumentException Throws this exception if the database is not supported. * @throws \InvalidArgumentException Throws this exception if the database is not supported.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function create(array $dbdata) : ConnectionInterface public static function create(array $dbdata) : ConnectionAbstract
{ {
switch ($dbdata['db']) { switch ($dbdata['db']) {
case DatabaseType::MYSQL: case DatabaseType::MYSQL:

View File

@ -59,7 +59,7 @@ final class MysqlConnection extends ConnectionAbstract
$this->dbdata = isset($dbdata) ? $dbdata : $this->dbdata; $this->dbdata = isset($dbdata) ? $dbdata : $this->dbdata;
if (!isset($this->dbdata['db'], $this->dbdata['host'], $this->dbdata['port'], $this->dbdata['database'], $this->dbdata['login'], $this->dbdata['password'])) { if (!isset($this->dbdata['db'], $this->dbdata['host'], $this->dbdata['port'], $this->dbdata['database'], $this->dbdata['login'], $this->dbdata['password'])) {
throw new InvalidConnectionConfigException(\json_encode($this->dbdata)); throw new InvalidConnectionConfigException((string) \json_encode($this->dbdata));
} }
$this->close(); $this->close();

View File

@ -58,7 +58,7 @@ final class PostgresConnection extends ConnectionAbstract
$this->dbdata = isset($dbdata) ? $dbdata : $this->dbdata; $this->dbdata = isset($dbdata) ? $dbdata : $this->dbdata;
if (!isset($this->dbdata['db'], $this->dbdata['host'], $this->dbdata['port'], $this->dbdata['database'], $this->dbdata['login'], $this->dbdata['password'])) { if (!isset($this->dbdata['db'], $this->dbdata['host'], $this->dbdata['port'], $this->dbdata['database'], $this->dbdata['login'], $this->dbdata['password'])) {
throw new InvalidConnectionConfigException(\json_encode($this->dbdata)); throw new InvalidConnectionConfigException((string) \json_encode($this->dbdata));
} }
$this->close(); $this->close();

View File

@ -16,7 +16,7 @@ namespace phpOMS\DataStorage\Database\Connection;
use phpOMS\DataStorage\Database\DatabaseStatus; use phpOMS\DataStorage\Database\DatabaseStatus;
use phpOMS\DataStorage\Database\DatabaseType; use phpOMS\DataStorage\Database\DatabaseType;
use phpOMS\DataStorage\Database\Query\Grammar\SqliteGrammar; use phpOMS\DataStorage\Database\Query\Grammar\SQLiteGrammar;
/** /**
* Database handler. * Database handler.
@ -29,7 +29,7 @@ use phpOMS\DataStorage\Database\Query\Grammar\SqliteGrammar;
* @link http://website.orange-management.de * @link http://website.orange-management.de
* @since 1.0.0 * @since 1.0.0
*/ */
final class SqliteConnection extends ConnectionAbstract final class SQLiteConnection extends ConnectionAbstract
{ {
/** /**
@ -43,8 +43,8 @@ final class SqliteConnection extends ConnectionAbstract
*/ */
public function __construct(array $dbdata) public function __construct(array $dbdata)
{ {
$this->type = DatabaseType::MYSQL; $this->type = DatabaseType::SQLITE;
$this->grammar = new SqliteGrammar(); $this->grammar = new SQLiteGrammar();
$this->connect($dbdata); $this->connect($dbdata);
} }
@ -65,9 +65,10 @@ final class SqliteConnection extends ConnectionAbstract
$this->status = DatabaseStatus::OK; $this->status = DatabaseStatus::OK;
} catch (\PDOException $e) { } catch (\PDOException $e) {
var_dump($e->getMessage());
$this->status = DatabaseStatus::MISSING_DATABASE; $this->status = DatabaseStatus::MISSING_DATABASE;
$this->con = null; $this->con = null;
} finally {
$this->dbdata['password'] = '****';
} }
} }
} }

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database; namespace phpOMS\DataStorage\Database;
use phpOMS\DataStorage\DataStorageConnectionInterface; use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
use phpOMS\DataStorage\Database\Query\Builder; use phpOMS\DataStorage\Database\Query\Builder;
use phpOMS\DataStorage\DataMapperInterface; use phpOMS\DataStorage\DataMapperInterface;
use phpOMS\Message\RequestAbstract; use phpOMS\Message\RequestAbstract;
@ -37,7 +37,7 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Database connection. * Database connection.
* *
* @var DataStorageConnectionInterface * @var ConnectionAbstract
* @since 1.0.0 * @since 1.0.0
*/ */
protected static $db = null; protected static $db = null;
@ -149,7 +149,7 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Highest mapper to know when to clear initialized objects * Highest mapper to know when to clear initialized objects
* *
* @var string * @var null|string
* @since 1.0.0 * @since 1.0.0
*/ */
protected static $parentMapper = null; protected static $parentMapper = null;
@ -195,13 +195,13 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Set database connection. * Set database connection.
* *
* @param DataStorageConnectionInterface $con Database connection * @param ConnectionAbstract $con Database connection
* *
* @return void * @return void
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function setConnection(DataStorageConnectionInterface $con) : void public static function setConnection(ConnectionAbstract $con) : void
{ {
self::$db = $con; self::$db = $con;
} }
@ -389,20 +389,20 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Create base model. * Create base model.
* *
* @param Object $obj Model to create * @param object $obj Model to create
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* *
* @return mixed * @return mixed
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function createModel($obj, \ReflectionClass $refClass) private static function createModel(object $obj, \ReflectionClass $refClass)
{ {
$query = new Builder(self::$db); $query = new Builder(self::$db);
$query->prefix(self::$db->getPrefix())->into(static::$table); $query->prefix(self::$db->getPrefix())->into(static::$table);
foreach (static::$columns as $key => $column) { foreach (static::$columns as $key => $column) {
$propertyName = \stripos($column['internal'], '/') !== false ? explode('/', $column['internal'])[0] : $column['internal']; $propertyName = \stripos($column['internal'], '/') !== false ? \explode('/', $column['internal'])[0] : $column['internal'];
if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) {
continue; continue;
} }
@ -425,11 +425,11 @@ class DataMapperAbstract implements DataMapperInterface
$query->insert($column['name'])->value($value, $column['type']); $query->insert($column['name'])->value($value, $column['type']);
} elseif ($column['name'] !== static::$primaryField) { } elseif ($column['name'] !== static::$primaryField) {
$tValue = $property->getValue($obj); $tValue = $property->getValue($obj);
if (stripos($column['internal'], '/') !== false) { if (\stripos($column['internal'], '/') !== false) {
$path = \explode('/', $column['internal']); $path = \explode('/', $column['internal']);
array_shift($path); \array_shift($path);
$path = implode('/', $path); $path = \implode('/', $path);
$tValue = ArrayUtils::getArray($path, $tValue, '/'); $tValue = ArrayUtils::getArray($path, $tValue, '/');
} }
@ -444,7 +444,7 @@ class DataMapperAbstract implements DataMapperInterface
} }
// if a table only has a single column = primary key column. This must be done otherwise the query is empty // if a table only has a single column = primary key column. This must be done otherwise the query is empty
if ($query->getType() === QueryType::EMPTY) { if ($query->getType() === QueryType::NONE) {
$query->insert(static::$primaryField)->value(0, static::$columns[static::$primaryField]['type']); $query->insert(static::$primaryField)->value(0, static::$columns[static::$primaryField]['type']);
} }
@ -475,11 +475,11 @@ class DataMapperAbstract implements DataMapperInterface
} }
$path = $column['internal']; $path = $column['internal'];
if (stripos($column['internal'], '/') !== false) { if (\stripos($column['internal'], '/') !== false) {
$path = \explode('/', $column['internal']); $path = \explode('/', $column['internal']);
array_shift($path); \array_shift($path);
$path = implode('/', $path); $path = \implode('/', $path);
} }
$property = ArrayUtils::getArray($path, $obj, '/'); $property = ArrayUtils::getArray($path, $obj, '/');
@ -512,14 +512,14 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Get id of object * Get id of object
* *
* @param Object $obj Model to create * @param object $obj Model to create
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* *
* @return mixed * @return mixed
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function getObjectId($obj, \ReflectionClass $refClass = null) private static function getObjectId(object $obj, \ReflectionClass $refClass = null)
{ {
$refClass = $refClass ?? new \ReflectionClass($obj); $refClass = $refClass ?? new \ReflectionClass($obj);
$refProp = $refClass->getProperty(static::$columns[static::$primaryField]['internal']); $refProp = $refClass->getProperty(static::$columns[static::$primaryField]['internal']);
@ -541,14 +541,14 @@ class DataMapperAbstract implements DataMapperInterface
* Set id to model * Set id to model
* *
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* @param Object $obj Object to create * @param object $obj Object to create
* @param mixed $objId Id to set * @param mixed $objId Id to set
* *
* @return void * @return void
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function setObjectId(\ReflectionClass $refClass, $obj, $objId) : void private static function setObjectId(\ReflectionClass $refClass, object $obj, $objId) : void
{ {
$refProp = $refClass->getProperty(static::$columns[static::$primaryField]['internal']); $refProp = $refClass->getProperty(static::$columns[static::$primaryField]['internal']);
@ -568,7 +568,7 @@ class DataMapperAbstract implements DataMapperInterface
* Create has many * Create has many
* *
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* @param Object $obj Object to create * @param object $obj Object to create
* @param mixed $objId Id to set * @param mixed $objId Id to set
* *
* @return void * @return void
@ -577,7 +577,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function createHasMany(\ReflectionClass $refClass, $obj, $objId) : void private static function createHasMany(\ReflectionClass $refClass, object $obj, $objId) : void
{ {
foreach (static::$hasMany as $propertyName => $rel) { foreach (static::$hasMany as $propertyName => $rel) {
$property = $refClass->getProperty($propertyName); $property = $refClass->getProperty($propertyName);
@ -602,7 +602,7 @@ class DataMapperAbstract implements DataMapperInterface
$relReflectionClass = null; $relReflectionClass = null;
foreach ($values as $key => &$value) { foreach ($values as $key => &$value) {
if (!is_object($value)) { if (!\is_object($value)) {
// Is scalar => already in database // Is scalar => already in database
$objsIds[$key] = $value; $objsIds[$key] = $value;
@ -672,7 +672,7 @@ class DataMapperAbstract implements DataMapperInterface
$objsIds = []; $objsIds = [];
foreach ($values as $key => &$value) { foreach ($values as $key => &$value) {
if (!is_object($value)) { if (!\is_array($value)) {
// Is scalar => already in database // Is scalar => already in database
$objsIds[$key] = $value; $objsIds[$key] = $value;
@ -706,14 +706,14 @@ class DataMapperAbstract implements DataMapperInterface
* Create has one * Create has one
* *
* @param \ReflectionClass $refClass Property name to initialize * @param \ReflectionClass $refClass Property name to initialize
* @param Object $obj Object to create * @param object $obj Object to create
* *
* @return mixed * @return mixed
* @todo implement??? * @todo implement???
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function createHasOne(\ReflectionClass $refClass, $obj) private static function createHasOne(\ReflectionClass $refClass, object $obj)
{ {
throw new \Exception(); throw new \Exception();
} }
@ -724,7 +724,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model * The reference is stored in the main model
* *
* @param string $propertyName Property name to initialize * @param string $propertyName Property name to initialize
* @param Object $obj Object to create * @param mixed $obj Object to create
* *
* @return mixed * @return mixed
* *
@ -732,7 +732,7 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function createOwnsOne(string $propertyName, $obj) private static function createOwnsOne(string $propertyName, $obj)
{ {
if (is_object($obj)) { if (\is_object($obj)) {
$mapper = static::$ownsOne[$propertyName]['mapper']; $mapper = static::$ownsOne[$propertyName]['mapper'];
$primaryKey = $mapper::getObjectId($obj); $primaryKey = $mapper::getObjectId($obj);
@ -760,7 +760,7 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function createOwnsOneArray(string $propertyName, array &$obj) private static function createOwnsOneArray(string $propertyName, array &$obj)
{ {
if (is_array($obj)) { if (\is_array($obj)) {
$mapper = static::$ownsOne[$propertyName]['mapper']; $mapper = static::$ownsOne[$propertyName]['mapper'];
$primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; $primaryKey = $obj[static::$columns[static::$primaryField]['internal']];
@ -780,7 +780,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model * The reference is stored in the main model
* *
* @param string $propertyName Property name to initialize * @param string $propertyName Property name to initialize
* @param Object $obj Object to create * @param mixed $obj Object to create
* *
* @return mixed * @return mixed
* *
@ -788,7 +788,7 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function createBelongsTo(string $propertyName, $obj) private static function createBelongsTo(string $propertyName, $obj)
{ {
if (is_object($obj)) { if (\is_object($obj)) {
/** @var string $mapper */ /** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper']; $mapper = static::$belongsTo[$propertyName]['mapper'];
$primaryKey = $mapper::getObjectId($obj); $primaryKey = $mapper::getObjectId($obj);
@ -817,7 +817,7 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function createBelongsToArray(string $propertyName, array $obj) private static function createBelongsToArray(string $propertyName, array $obj)
{ {
if (is_array($obj)) { if (\is_array($obj)) {
/** @var string $mapper */ /** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper']; $mapper = static::$belongsTo[$propertyName]['mapper'];
$primaryKey = $obj[static::$columns[static::$primaryField]['internal']]; $primaryKey = $obj[static::$columns[static::$primaryField]['internal']];
@ -890,12 +890,12 @@ class DataMapperAbstract implements DataMapperInterface
} elseif ($type === 'DateTime') { } elseif ($type === 'DateTime') {
return $value->format('Y-m-d H:i:s'); return $value->format('Y-m-d H:i:s');
} elseif ($type === 'Json' || $type === 'jsonSerializable') { } elseif ($type === 'Json' || $type === 'jsonSerializable') {
return \json_encode($value); return (string) \json_encode($value);
} elseif ($type === 'Serializable') { } elseif ($type === 'Serializable') {
return $value->serialize(); return $value->serialize();
} elseif ($value instanceof \JsonSerializable) { } elseif ($value instanceof \JsonSerializable) {
return \json_encode($value->jsonSerialize()); return (string) \json_encode($value->jsonSerialize());
} elseif (is_object($value) && \method_exists($value, 'getId')) { } elseif (\is_object($value) && method_exists($value, 'getId')) {
return $value->getId(); return $value->getId();
} }
@ -905,9 +905,11 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Update has many * Update has many
* *
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* @param Object $obj Object to create * @param object $obj Object to create
* @param mixed $objId Id to set * @param mixed $objId Id to set
* @param int $relations Create all relations as well
* @param int $depth Depth of relations to update (default = 1 = none)
* *
* @return void * @return void
* *
@ -915,7 +917,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function updateHasMany(\ReflectionClass $refClass, $obj, $objId) : void private static function updateHasMany(\ReflectionClass $refClass, object $obj, $objId, int $relations = RelationType::ALL, $depth = 1) : void
{ {
$objsIds = []; $objsIds = [];
@ -942,7 +944,7 @@ class DataMapperAbstract implements DataMapperInterface
$objsIds[$propertyName] = []; $objsIds[$propertyName] = [];
foreach ($values as $key => &$value) { foreach ($values as $key => &$value) {
if (!is_object($value)) { if (!\is_object($value)) {
// Is scalar => already in database // Is scalar => already in database
$objsIds[$propertyName][$key] = $value; $objsIds[$propertyName][$key] = $value;
@ -957,7 +959,7 @@ class DataMapperAbstract implements DataMapperInterface
// already in db // already in db
if (!empty($primaryKey)) { if (!empty($primaryKey)) {
$mapper::update($value); $mapper::update($value, $relations, $depth);
$objsIds[$propertyName][$key] = $value; $objsIds[$propertyName][$key] = $value;
@ -1055,24 +1057,22 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model * The reference is stored in the main model
* *
* @param string $propertyName Property name to initialize * @param string $propertyName Property name to initialize
* @param Object $obj Object to update * @param object $obj Object to update
* @param int $relations Create all relations as well
* @param int $depth Depth of relations to update (default = 1 = none)
* *
* @return mixed * @return mixed
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function updateOwnsOne(string $propertyName, $obj) private static function updateOwnsOne(string $propertyName, object $obj, int $relations = RelationType::ALL, int $depth = 1)
{ {
if (is_object($obj)) { /** @var string $mapper */
/** @var string $mapper */ $mapper = static::$ownsOne[$propertyName]['mapper'];
$mapper = static::$ownsOne[$propertyName]['mapper'];
// todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one? // todo: delete owned one object is not recommended since it can be owned by by something else? or does owns one mean that nothing else can have a relation to this one?
return $mapper::update($obj); return $mapper::update($obj, $relations, $depth);
}
return $obj;
} }
/** /**
@ -1081,19 +1081,21 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model * The reference is stored in the main model
* *
* @param string $propertyName Property name to initialize * @param string $propertyName Property name to initialize
* @param Object $obj Object to update * @param mixed $obj Object to update
* @param int $relations Create all relations as well
* @param int $depth Depth of relations to update (default = 1 = none)
* *
* @return mixed * @return mixed
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function updateBelongsTo(string $propertyName, $obj) private static function updateBelongsTo(string $propertyName, $obj, int $relations = RelationType::ALL, int $depth = 1)
{ {
if (is_object($obj)) { if (\is_object($obj)) {
/** @var string $mapper */ /** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper']; $mapper = static::$belongsTo[$propertyName]['mapper'];
return $mapper::update($obj); return $mapper::update($obj, $relations, $depth);
} }
return $obj; return $obj;
@ -1102,15 +1104,17 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Update object in db. * Update object in db.
* *
* @param Object $obj Model to update * @param object $obj Model to update
* @param mixed $objId Model id * @param mixed $objId Model id
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* @param int $relations Create all relations as well
* @param int $depth Depth of relations to update (default = 1 = none)
* *
* @return void * @return void
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function updateModel($obj, $objId, \ReflectionClass $refClass = null) : void private static function updateModel(object $obj, $objId, \ReflectionClass $refClass = null, int $relations = RelationType::ALL, int $depth = 1) : void
{ {
$query = new Builder(self::$db); $query = new Builder(self::$db);
$query->prefix(self::$db->getPrefix()) $query->prefix(self::$db->getPrefix())
@ -1118,7 +1122,7 @@ class DataMapperAbstract implements DataMapperInterface
->where(static::$table . '.' . static::$primaryField, '=', $objId); ->where(static::$table . '.' . static::$primaryField, '=', $objId);
foreach (static::$columns as $key => $column) { foreach (static::$columns as $key => $column) {
$propertyName = \stripos($column['internal'], '/') !== false ? explode('/', $column['internal'])[0] : $column['internal']; $propertyName = \stripos($column['internal'], '/') !== false ? \explode('/', $column['internal'])[0] : $column['internal'];
if (isset(static::$hasMany[$propertyName]) if (isset(static::$hasMany[$propertyName])
|| isset(static::$hasOne[$propertyName]) || isset(static::$hasOne[$propertyName])
|| $column['internal'] === static::$primaryField || $column['internal'] === static::$primaryField
@ -1126,6 +1130,7 @@ class DataMapperAbstract implements DataMapperInterface
continue; continue;
} }
$refClass = $refClass ?? new \ReflectionClass($obj);
$property = $refClass->getProperty($propertyName); $property = $refClass->getProperty($propertyName);
if (!($isPublic = $property->isPublic())) { if (!($isPublic = $property->isPublic())) {
@ -1133,24 +1138,24 @@ class DataMapperAbstract implements DataMapperInterface
} }
if (isset(static::$ownsOne[$propertyName])) { if (isset(static::$ownsOne[$propertyName])) {
$id = self::updateOwnsOne($propertyName, $property->getValue($obj)); $id = self::updateOwnsOne($propertyName, $property->getValue($obj), $relations, $depth);
$value = self::parseValue($column['type'], $id); $value = self::parseValue($column['type'], $id);
// todo: should not be done if the id didn't change. but for now don't know if id changed // todo: should not be done if the id didn't change. but for now don't know if id changed
$query->set([static::$table . '.' . $column['name'] => $value], $column['type']); $query->set([static::$table . '.' . $column['name'] => $value], $column['type']);
} elseif (isset(static::$belongsTo[$propertyName])) { } elseif (isset(static::$belongsTo[$propertyName])) {
$id = self::updateBelongsTo($propertyName, $property->getValue($obj)); $id = self::updateBelongsTo($propertyName, $property->getValue($obj), $relations, $depth);
$value = self::parseValue($column['type'], $id); $value = self::parseValue($column['type'], $id);
// todo: should not be done if the id didn't change. but for now don't know if id changed // todo: should not be done if the id didn't change. but for now don't know if id changed
$query->set([static::$table . '.' . $column['name'] => $value], $column['type']); $query->set([static::$table . '.' . $column['name'] => $value], $column['type']);
} elseif ($column['name'] !== static::$primaryField) { } elseif ($column['name'] !== static::$primaryField) {
$tValue = $property->getValue($obj); $tValue = $property->getValue($obj);
if (stripos($column['internal'], '/') !== false) { if (\stripos($column['internal'], '/') !== false) {
$path = \explode('/', $column['internal']); $path = \explode('/', $column['internal']);
array_shift($path); \array_shift($path);
$path = implode('/', $path); $path = \implode('/', $path);
$tValue = ArrayUtils::getArray($path, $tValue, '/'); $tValue = ArrayUtils::getArray($path, $tValue, '/');
} }
$value = self::parseValue($column['type'], $tValue); $value = self::parseValue($column['type'], $tValue);
@ -1171,12 +1176,13 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @param mixed $obj Object reference (gets filled with insert id) * @param mixed $obj Object reference (gets filled with insert id)
* @param int $relations Create all relations as well * @param int $relations Create all relations as well
* @param int $depth Depth of relations to update (default = 1 = none)
* *
* @return mixed * @return mixed
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function update($obj, int $relations = RelationType::ALL) public static function update($obj, int $relations = RelationType::ALL, int $depth = 1)
{ {
self::extend(__CLASS__); self::extend(__CLASS__);
@ -1188,8 +1194,11 @@ class DataMapperAbstract implements DataMapperInterface
$objId = self::getObjectId($obj, $refClass); $objId = self::getObjectId($obj, $refClass);
$update = true; $update = true;
// todo: maybe don't remove obj and just update cache... ? since it might have to be loaded again if ($depth < 1) {
self::removeInitialized(static::class, $objId); return $objId;
}
self::addInitialized(static::class, $objId, $obj);
if (empty($objId)) { if (empty($objId)) {
$update = false; $update = false;
@ -1197,11 +1206,11 @@ class DataMapperAbstract implements DataMapperInterface
} }
if ($relations === RelationType::ALL) { if ($relations === RelationType::ALL) {
self::updateHasMany($refClass, $obj, $objId); self::updateHasMany($refClass, $obj, $objId, --$depth);
} }
if ($update) { if ($update) {
self::updateModel($obj, $objId, $refClass); self::updateModel($obj, $objId, $refClass, --$depth);
} }
return $objId; return $objId;
@ -1211,7 +1220,7 @@ class DataMapperAbstract implements DataMapperInterface
* Delete has many * Delete has many
* *
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
* @param Object $obj Object to create * @param object $obj Object to create
* @param mixed $objId Id to set * @param mixed $objId Id to set
* @param int $relations Delete all relations as well * @param int $relations Delete all relations as well
* *
@ -1221,7 +1230,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function deleteHasMany(\ReflectionClass $refClass, $obj, $objId, int $relations) : void private static function deleteHasMany(\ReflectionClass $refClass, object $obj, $objId, int $relations) : void
{ {
foreach (static::$hasMany as $propertyName => $rel) { foreach (static::$hasMany as $propertyName => $rel) {
$property = $refClass->getProperty($propertyName); $property = $refClass->getProperty($propertyName);
@ -1246,7 +1255,7 @@ class DataMapperAbstract implements DataMapperInterface
$relReflectionClass = null; $relReflectionClass = null;
foreach ($values as $key => &$value) { foreach ($values as $key => &$value) {
if (!is_object($value)) { if (!\is_object($value)) {
// Is scalar => already in database // Is scalar => already in database
$objsIds[$key] = $value; $objsIds[$key] = $value;
@ -1284,7 +1293,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model * The reference is stored in the main model
* *
* @param string $propertyName Property name to initialize * @param string $propertyName Property name to initialize
* @param Object $obj Object to delete * @param mixed $obj Object to delete
* *
* @return mixed * @return mixed
* *
@ -1292,7 +1301,7 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function deleteOwnsOne(string $propertyName, $obj) private static function deleteOwnsOne(string $propertyName, $obj)
{ {
if (is_object($obj)) { if (\is_object($obj)) {
/** @var string $mapper */ /** @var string $mapper */
$mapper = static::$ownsOne[$propertyName]['mapper']; $mapper = static::$ownsOne[$propertyName]['mapper'];
@ -1309,7 +1318,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model * The reference is stored in the main model
* *
* @param string $propertyName Property name to initialize * @param string $propertyName Property name to initialize
* @param Object $obj Object to delete * @param mixed $obj Object to delete
* *
* @return mixed * @return mixed
* *
@ -1317,7 +1326,7 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function deleteBelongsTo(string $propertyName, $obj) private static function deleteBelongsTo(string $propertyName, $obj)
{ {
if (is_object($obj)) { if (\is_object($obj)) {
/** @var string $mapper */ /** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper']; $mapper = static::$belongsTo[$propertyName]['mapper'];
@ -1330,7 +1339,7 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Delete object in db. * Delete object in db.
* *
* @param Object $obj Model to delete * @param object $obj Model to delete
* @param mixed $objId Model id * @param mixed $objId Model id
* @param int $relations Delete all relations as well * @param int $relations Delete all relations as well
* @param \ReflectionClass $refClass Reflection class * @param \ReflectionClass $refClass Reflection class
@ -1339,7 +1348,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function deleteModel($obj, $objId, int $relations = RelationType::REFERENCE, \ReflectionClass $refClass = null) : void private static function deleteModel(object $obj, $objId, int $relations = RelationType::REFERENCE, \ReflectionClass $refClass = null) : void
{ {
$query = new Builder(self::$db); $query = new Builder(self::$db);
$query->prefix(self::$db->getPrefix()) $query->prefix(self::$db->getPrefix())
@ -1347,6 +1356,7 @@ class DataMapperAbstract implements DataMapperInterface
->from(static::$table) ->from(static::$table)
->where(static::$table . '.' . static::$primaryField, '=', $objId); ->where(static::$table . '.' . static::$primaryField, '=', $objId);
$refClass = $refClass ?? new \ReflectionClass($obj);
$properties = $refClass->getProperties(); $properties = $refClass->getProperties();
if ($relations === RelationType::ALL) { if ($relations === RelationType::ALL) {
@ -1486,7 +1496,7 @@ class DataMapperAbstract implements DataMapperInterface
$parts = \explode('\\', $class); $parts = \explode('\\', $class);
$name = $parts[$c = (count($parts) - 1)]; $name = $parts[$c = (count($parts) - 1)];
$parts[$c] = 'Null' . $name; $parts[$c] = 'Null' . $name;
$class = implode('\\', $parts); $class = \implode('\\', $parts);
} }
if (!isset($obj)) { if (!isset($obj)) {
@ -1507,7 +1517,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateManyToMany(array $result, &$obj, int $depth = null) : void public static function populateManyToMany(array $result, &$obj, int $depth = 3) : void
{ {
// todo: maybe pass reflectionClass as optional parameter for performance increase // todo: maybe pass reflectionClass as optional parameter for performance increase
$refClass = new \ReflectionClass($obj); $refClass = new \ReflectionClass($obj);
@ -1523,7 +1533,7 @@ class DataMapperAbstract implements DataMapperInterface
} }
$objects = $mapper::get($values, RelationType::ALL, null, $depth); $objects = $mapper::get($values, RelationType::ALL, null, $depth);
$refProp->setValue($obj, !is_array($objects) ? [$objects->getId() => $objects] : $objects); $refProp->setValue($obj, !\is_array($objects) ? [$objects->getId() => $objects] : $objects);
if (!$accessible) { if (!$accessible) {
$refProp->setAccessible(false); $refProp->setAccessible(false);
@ -1543,7 +1553,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateManyToManyArray(array $result, array &$obj, int $depth = null) : void public static function populateManyToManyArray(array $result, array &$obj, int $depth = 3) : void
{ {
foreach ($result as $member => $values) { foreach ($result as $member => $values) {
if (!empty($values)) { if (!empty($values)) {
@ -1568,7 +1578,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateHasOne(&$obj, int $depth = null) : void public static function populateHasOne(&$obj, int $depth = 3) : void
{ {
$refClass = new \ReflectionClass($obj); $refClass = new \ReflectionClass($obj);
@ -1589,7 +1599,7 @@ class DataMapperAbstract implements DataMapperInterface
continue; continue;
} }
$id = is_object($id) ? self::getObjectId($id) : $id; $id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth); $value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$refProp->setValue($obj, $value); $refProp->setValue($obj, $value);
@ -1613,7 +1623,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateHasOneArray(array &$obj, int $depth = null) : void public static function populateHasOneArray(array &$obj, int $depth = 3) : void
{ {
foreach (static::$hasOne as $member => $one) { foreach (static::$hasOne as $member => $one) {
/** @var string $mapper */ /** @var string $mapper */
@ -1634,7 +1644,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateOwnsOne(&$obj, int $depth = null) : void public static function populateOwnsOne(&$obj, int $depth = 3) : void
{ {
$refClass = new \ReflectionClass($obj); $refClass = new \ReflectionClass($obj);
@ -1655,7 +1665,7 @@ class DataMapperAbstract implements DataMapperInterface
continue; continue;
} }
$id = is_object($id) ? self::getObjectId($id) : $id; $id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth); $value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$refProp->setValue($obj, $value); $refProp->setValue($obj, $value);
@ -1679,7 +1689,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateOwnsOneArray(array &$obj, int $depth = null) : void public static function populateOwnsOneArray(array &$obj, int $depth = 3) : void
{ {
foreach (static::$ownsOne as $member => $one) { foreach (static::$ownsOne as $member => $one) {
/** @var string $mapper */ /** @var string $mapper */
@ -1700,7 +1710,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateBelongsTo(&$obj, int $depth = null) : void public static function populateBelongsTo(&$obj, int $depth = 3) : void
{ {
$refClass = new \ReflectionClass($obj); $refClass = new \ReflectionClass($obj);
@ -1721,7 +1731,7 @@ class DataMapperAbstract implements DataMapperInterface
continue; continue;
} }
$id = is_object($id) ? self::getObjectId($id) : $id; $id = \is_object($id) ? self::getObjectId($id) : $id;
$value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth); $value = self::getInitialized($mapper, $id) ?? $mapper::get($id, RelationType::ALL, null, $depth);
$refProp->setValue($obj, $value); $refProp->setValue($obj, $value);
@ -1745,7 +1755,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function populateBelongsToArray(array &$obj, int $depth = null) : void public static function populateBelongsToArray(array &$obj, int $depth = 3) : void
{ {
foreach (static::$belongsTo as $member => $one) { foreach (static::$belongsTo as $member => $one) {
/** @var string $mapper */ /** @var string $mapper */
@ -1775,9 +1785,11 @@ class DataMapperAbstract implements DataMapperInterface
continue; continue;
} }
$hasPath = false; $hasPath = false;
$aValue = [];
$arrayPath = '';
if (stripos(static::$columns[$column]['internal'], '/') !== false) { if (\stripos(static::$columns[$column]['internal'], '/') !== false) {
$hasPath = true; $hasPath = true;
$path = \explode('/', static::$columns[$column]['internal']); $path = \explode('/', static::$columns[$column]['internal']);
$refProp = $refClass->getProperty($path[0]); $refProp = $refClass->getProperty($path[0]);
@ -1786,9 +1798,9 @@ class DataMapperAbstract implements DataMapperInterface
$refProp->setAccessible(true); $refProp->setAccessible(true);
} }
array_shift($path); \array_shift($path);
$path = implode('/', $path); $arrayPath = \implode('/', $path);
$aValue = $refProp->getValue($obj); $aValue = $refProp->getValue($obj);
} else { } else {
$refProp = $refClass->getProperty(static::$columns[$column]['internal']); $refProp = $refClass->getProperty(static::$columns[$column]['internal']);
@ -1804,20 +1816,20 @@ class DataMapperAbstract implements DataMapperInterface
} }
if ($hasPath) { if ($hasPath) {
$value = ArrayUtils::setArray($path, $aValue, $value, '/', true); $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true);
} }
$refProp->setValue($obj, $value); $refProp->setValue($obj, $value);
} elseif (static::$columns[$column]['type'] === 'DateTime') { } elseif (static::$columns[$column]['type'] === 'DateTime') {
$value = new \DateTime($value ?? ''); $value = new \DateTime($value ?? '');
if ($hasPath) { if ($hasPath) {
$value = ArrayUtils::setArray($path, $aValue, $value, '/', true); $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true);
} }
$refProp->setValue($obj, $value); $refProp->setValue($obj, $value);
} elseif (static::$columns[$column]['type'] === 'Json') { } elseif (static::$columns[$column]['type'] === 'Json') {
if ($hasPath) { if ($hasPath) {
$value = ArrayUtils::setArray($path, $aValue, $value, '/', true); $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true);
} }
$refProp->setValue($obj, \json_decode($value, true)); $refProp->setValue($obj, \json_decode($value, true));
@ -1851,11 +1863,11 @@ class DataMapperAbstract implements DataMapperInterface
foreach ($result as $column => $value) { foreach ($result as $column => $value) {
if (isset(static::$columns[$column]['internal'])) { if (isset(static::$columns[$column]['internal'])) {
$path = static::$columns[$column]['internal']; $path = static::$columns[$column]['internal'];
if (stripos($path, '/') !== false) { if (\stripos($path, '/') !== false) {
$path = \explode('/', $path); $path = \explode('/', $path);
array_shift($path); \array_shift($path);
$path = implode('/', $path); $path = \implode('/', $path);
} }
if (\in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) { if (\in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) {
@ -1887,9 +1899,9 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function get($primaryKey, int $relations = RelationType::ALL, $fill = null, int $depth = null) public static function get($primaryKey, int $relations = RelationType::ALL, $fill = null, int $depth = 3)
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return $primaryKey; return $primaryKey;
} }
@ -1925,7 +1937,7 @@ class DataMapperAbstract implements DataMapperInterface
self::addInitialized(static::class, $value, $obj[$value]); self::addInitialized(static::class, $value, $obj[$value]);
} }
self::fillRelations($obj, $relations, isset($depth) ? --$depth : null); self::fillRelations($obj, $relations, --$depth);
self::clear(); self::clear();
$countResulsts = count($obj); $countResulsts = count($obj);
@ -1953,7 +1965,7 @@ class DataMapperAbstract implements DataMapperInterface
$parts = \explode('\\', $class); $parts = \explode('\\', $class);
$name = $parts[$c = (count($parts) - 1)]; $name = $parts[$c = (count($parts) - 1)];
$parts[$c] = 'Null' . $name; $parts[$c] = 'Null' . $name;
$class = implode('\\', $parts); $class = \implode('\\', $parts);
return new $class(); return new $class();
} }
@ -1969,9 +1981,9 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getArray($primaryKey, int $relations = RelationType::ALL, int $depth = null) : array public static function getArray($primaryKey, int $relations = RelationType::ALL, int $depth = 3) : array
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return $primaryKey; return $primaryKey;
} }
@ -1995,7 +2007,7 @@ class DataMapperAbstract implements DataMapperInterface
self::addInitialized(static::class, $value, $obj[$value]); self::addInitialized(static::class, $value, $obj[$value]);
} }
self::fillRelationsArray($obj, $relations, isset($depth) ? --$depth : null); self::fillRelationsArray($obj, $relations, --$depth);
self::clear(); self::clear();
return count($obj) === 1 ? reset($obj) : $obj; return count($obj) === 1 ? reset($obj) : $obj;
@ -2014,9 +2026,9 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getFor($refKey, string $ref, int $relations = RelationType::ALL, $fill = null, int $depth = null) public static function getFor($refKey, string $ref, int $relations = RelationType::ALL, $fill = null, int $depth = 3)
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return $refKey; return $refKey;
} }
@ -2038,7 +2050,7 @@ class DataMapperAbstract implements DataMapperInterface
$toLoad = self::getPrimaryKeysBy($value, self::getColumnByMember($ref)); $toLoad = self::getPrimaryKeysBy($value, self::getColumnByMember($ref));
} }
$obj[$value] = self::get($toLoad, $relations, $fill, isset($depth) ? --$depth : null); $obj[$value] = self::get($toLoad, $relations, $fill, --$depth);
} }
$countResulsts = count($obj); $countResulsts = count($obj);
@ -2101,10 +2113,10 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getAll(int $relations = RelationType::ALL, int $depth = null, string $lang = '') : array public static function getAll(int $relations = RelationType::ALL, int $depth = 3, string $lang = '') : array
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return null; return [];
} }
if (!isset(self::$parentMapper)) { if (!isset(self::$parentMapper)) {
@ -2112,7 +2124,7 @@ class DataMapperAbstract implements DataMapperInterface
} }
$obj = self::populateIterable(self::getAllRaw($lang)); $obj = self::populateIterable(self::getAllRaw($lang));
self::fillRelations($obj, $relations, isset($depth) ? --$depth : null); self::fillRelations($obj, $relations, --$depth);
self::clear(); self::clear();
return $obj; return $obj;
@ -2129,10 +2141,10 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getAllArray(int $relations = RelationType::ALL, int $depth = null, string $lang = '') : array public static function getAllArray(int $relations = RelationType::ALL, int $depth = 3, string $lang = '') : array
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return null; return [];
} }
if (!isset(self::$parentMapper)) { if (!isset(self::$parentMapper)) {
@ -2140,7 +2152,7 @@ class DataMapperAbstract implements DataMapperInterface
} }
$obj = self::populateIterableArray(self::getAllRaw($lang)); $obj = self::populateIterableArray(self::getAllRaw($lang));
self::fillRelationsArray($obj, $relations, isset($depth) ? --$depth : null); self::fillRelationsArray($obj, $relations, --$depth);
self::clear(); self::clear();
return $obj; return $obj;
@ -2160,7 +2172,13 @@ class DataMapperAbstract implements DataMapperInterface
$sth = self::$db->con->prepare($query->toSql()); $sth = self::$db->con->prepare($query->toSql());
$sth->execute(); $sth->execute();
return self::populateIterable($sth->fetchAll(\PDO::FETCH_ASSOC)); $result = $sth->fetchAll(\PDO::FETCH_ASSOC);
if ($result === false) {
return [];
}
return self::populateIterable($result);
} }
/** /**
@ -2174,14 +2192,14 @@ class DataMapperAbstract implements DataMapperInterface
* @param int $depth Relation depth * @param int $depth Relation depth
* @param string $lang Language * @param string $lang Language
* *
* @return mixed * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getNewest(int $limit = 1, Builder $query = null, int $relations = RelationType::ALL, int $depth = null, string $lang = '') : array public static function getNewest(int $limit = 1, Builder $query = null, int $relations = RelationType::ALL, int $depth = 3, string $lang = '') : array
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return null; return [];
} }
self::extend(__CLASS__); self::extend(__CLASS__);
@ -2204,13 +2222,12 @@ class DataMapperAbstract implements DataMapperInterface
$sth->execute(); $sth->execute();
$results = $sth->fetchAll(\PDO::FETCH_ASSOC); $results = $sth->fetchAll(\PDO::FETCH_ASSOC);
$obj = self::populateIterable(is_bool($results) ? [] : $results); $obj = self::populateIterable($results === false ? [] : $results);
self::fillRelations($obj, $relations, isset($depth) ? --$depth : null); self::fillRelations($obj, $relations, --$depth);
self::clear(); self::clear();
return $obj; return $obj;
} }
/** /**
@ -2224,20 +2241,20 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getAllByQuery(Builder $query, int $relations = RelationType::ALL, int $depth = null) : array public static function getAllByQuery(Builder $query, int $relations = RelationType::ALL, int $depth = 3) : array
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return null; return [];
} }
$sth = self::$db->con->prepare($query->toSql()); $sth = self::$db->con->prepare($query->toSql());
$sth->execute(); $sth->execute();
$results = $sth->fetchAll(\PDO::FETCH_ASSOC); $results = $sth->fetchAll(\PDO::FETCH_ASSOC);
$results = is_bool($results) ? [] : $results; $results = $results === false ? [] : $results;
$obj = self::populateIterable($results); $obj = self::populateIterable($results);
self::fillRelations($obj, $relations, isset($depth) ? --$depth : null); self::fillRelations($obj, $relations, --$depth);
self::clear(); self::clear();
return $obj; return $obj;
@ -2254,9 +2271,9 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function getRandom(int $amount = 1, int $relations = RelationType::ALL, int $depth = null) public static function getRandom(int $amount = 1, int $relations = RelationType::ALL, int $depth = 3)
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return null; return null;
} }
@ -2275,7 +2292,7 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Fill object with relations * Fill object with relations
* *
* @param mixed $obj Objects to fill * @param array $obj Objects to fill
* @param int $relations Relations type * @param int $relations Relations type
* @param int $depth Relation depth * @param int $depth Relation depth
* *
@ -2283,9 +2300,9 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function fillRelations(array &$obj, int $relations = RelationType::ALL, int $depth = null) : void public static function fillRelations(array &$obj, int $relations = RelationType::ALL, int $depth = 3) : void
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return; return;
} }
@ -2325,7 +2342,7 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Fill object with relations * Fill object with relations
* *
* @param mixed $obj Objects to fill * @param array $obj Objects to fill
* @param int $relations Relations type * @param int $relations Relations type
* @param int $depth Relation depth * @param int $depth Relation depth
* *
@ -2333,9 +2350,9 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function fillRelationsArray(array &$obj, int $relations = RelationType::ALL, int $depth = null) : void public static function fillRelationsArray(array &$obj, int $relations = RelationType::ALL, int $depth = 3) : void
{ {
if (isset($depth) && $depth < 1) { if ($depth < 1) {
return; return;
} }
@ -2377,7 +2394,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @param mixed $primaryKey Key * @param mixed $primaryKey Key
* *
* @return mixed * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@ -2391,7 +2408,7 @@ class DataMapperAbstract implements DataMapperInterface
$results = $sth->fetch(\PDO::FETCH_ASSOC); $results = $sth->fetch(\PDO::FETCH_ASSOC);
return is_bool($results) ? [] : $results; return $results === false ? [] : $results;
} }
/** /**
@ -2415,9 +2432,12 @@ class DataMapperAbstract implements DataMapperInterface
$sth = self::$db->con->prepare($query->toSql()); $sth = self::$db->con->prepare($query->toSql());
$sth->execute(); $sth->execute();
$results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); $result = $sth->fetchAll(\PDO::FETCH_NUM);
if ($result === false) {
return [];
}
return $results; return \array_column($result, 0);
} }
/** /**
@ -2441,9 +2461,12 @@ class DataMapperAbstract implements DataMapperInterface
$sth = self::$db->con->prepare($query->toSql()); $sth = self::$db->con->prepare($query->toSql());
$sth->execute(); $sth->execute();
$results = array_column($sth->fetchAll(\PDO::FETCH_NUM) ?? [], 0); $result = $sth->fetchAll(\PDO::FETCH_NUM);
if ($result === false) {
return [];
}
return $results; return \array_column($result, 0);
} }
/** /**
@ -2468,7 +2491,7 @@ class DataMapperAbstract implements DataMapperInterface
$results = $sth->fetchAll(\PDO::FETCH_ASSOC); $results = $sth->fetchAll(\PDO::FETCH_ASSOC);
return is_bool($results) ? [] : $results; return $results === false ? [] : $results;
} }
/** /**
@ -2608,7 +2631,7 @@ class DataMapperAbstract implements DataMapperInterface
* *
* @since 1.0.0 * @since 1.0.0
*/ */
private static function addInitialized(string $mapper, $id, $obj = null) : void private static function addInitialized(string $mapper, $id, object $obj = null) : void
{ {
if (!isset(self::$initObjects[$mapper])) { if (!isset(self::$initObjects[$mapper])) {
self::$initObjects[$mapper] = []; self::$initObjects[$mapper] = [];
@ -2686,7 +2709,7 @@ class DataMapperAbstract implements DataMapperInterface
$results = $sth->fetchAll(\PDO::FETCH_ASSOC); $results = $sth->fetchAll(\PDO::FETCH_ASSOC);
return count($results) === 0; return $results && count($results) === 0;
} }
/** /**
@ -2714,7 +2737,7 @@ class DataMapperAbstract implements DataMapperInterface
/** /**
* Test if object is null object * Test if object is null object
* *
* @param object $obj Object to check * @param mixed $obj Object to check
* *
* @return bool * @return bool
* *
@ -2722,6 +2745,6 @@ class DataMapperAbstract implements DataMapperInterface
*/ */
private static function isNullObject($obj) : bool private static function isNullObject($obj) : bool
{ {
return is_object($obj) && strpos(get_class($obj), '\Null') !== false; return \is_object($obj) && \strpos(\get_class($obj), '\Null') !== false;
} }
} }

View File

@ -30,7 +30,7 @@ abstract class DatabaseType extends Enum
{ {
public const MYSQL = 'mysql'; /* MySQL */ public const MYSQL = 'mysql'; /* MySQL */
public const SQLITE = 'sqlite'; /* SQLITE */ public const SQLITE = 'sqlite'; /* SQLITE */
public const PGSQL = 2; /* PostgreSQL */ public const PGSQL = 'postgresql'; /* PostgreSQL */
public const ORACLE = 3; /* Oracle */ public const ORACLE = 3; /* Oracle */
public const SQLSRV = 'mssql'; /* Microsoft SQL Server */ public const SQLSRV = 'mssql'; /* Microsoft SQL Server */
} }

View File

@ -95,7 +95,7 @@ abstract class GrammarAbstract
{ {
return trim( return trim(
implode(' ', implode(' ',
array_filter( \array_filter(
$this->compileComponents($query), $this->compileComponents($query),
function ($value) { function ($value) {
return (string) $value !== ''; return (string) $value !== '';
@ -169,13 +169,13 @@ abstract class GrammarAbstract
$expression = ''; $expression = '';
foreach ($elements as $key => $element) { foreach ($elements as $key => $element) {
if (is_string($element) && $element !== '*') { if (\is_string($element) && $element !== '*') {
if (strpos($element, '.') === false) { if (\strpos($element, '.') === false) {
$prefix = ''; $prefix = '';
} }
$expression .= $this->compileSystem($element, $prefix) . ', '; $expression .= $this->compileSystem($element, $prefix) . ', ';
} elseif (is_string($element) && $element === '*') { } elseif (\is_string($element) && $element === '*') {
$expression .= '*, '; $expression .= '*, ';
} elseif ($element instanceof \Closure) { } elseif ($element instanceof \Closure) {
$expression .= $element() . ', '; $expression .= $element() . ', ';
@ -204,9 +204,9 @@ abstract class GrammarAbstract
$expression = ''; $expression = '';
foreach ($elements as $key => $element) { foreach ($elements as $key => $element) {
if (is_string($element) && $element !== '*') { if (\is_string($element) && $element !== '*') {
$expression .= $this->compileSystem($element, $prefix) . ', '; $expression .= $this->compileSystem($element, $prefix) . ', ';
} elseif (is_string($element) && $element === '*') { } elseif (\is_string($element) && $element === '*') {
$expression .= '*, '; $expression .= '*, ';
} elseif ($element instanceof \Closure) { } elseif ($element instanceof \Closure) {
$expression .= $element() . ', '; $expression .= $element() . ', ';
@ -225,20 +225,20 @@ abstract class GrammarAbstract
* *
* A system is a table, a sub query or special keyword. * A system is a table, a sub query or special keyword.
* *
* @param array|string $system System * @param string $system System
* @param string $prefix Prefix for table * @param string $prefix Prefix for table
* *
* @return string * @return string
* *
* @since 1.0.0 * @since 1.0.0
*/ */
protected function compileSystem($system, string $prefix = '') : string protected function compileSystem(string $system, string $prefix = '') : string
{ {
// todo: this is a bad way to handle select count(*) which doesn't need a prefix. Maybe remove prefixes in total? // todo: this is a bad way to handle select count(*) which doesn't need a prefix. Maybe remove prefixes in total?
$identifier = $this->systemIdentifier; $identifier = $this->systemIdentifier;
foreach ($this->specialKeywords as $keyword) { foreach ($this->specialKeywords as $keyword) {
if (strrpos($system, $keyword, -strlen($system)) !== false) { if (\strrpos($system, $keyword, -\strlen($system)) !== false) {
$prefix = ''; $prefix = '';
$identifier = ''; $identifier = '';
} }

View File

@ -38,7 +38,7 @@ final class Builder extends BuilderAbstract
/** /**
* Columns. * Columns.
* *
* @var array<string, array<string, string>> * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
public $selects = []; public $selects = [];
@ -46,7 +46,7 @@ final class Builder extends BuilderAbstract
/** /**
* Columns. * Columns.
* *
* @var array<string, array<string, string>> * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
public $updates = []; public $updates = [];
@ -293,7 +293,7 @@ final class Builder extends BuilderAbstract
/** /**
* Bind parameter. * Bind parameter.
* *
* @param string|array|\Closure $binds Binds * @param mixed $binds Binds
* *
* @return Builder * @return Builder
* *
@ -336,18 +336,6 @@ final class Builder extends BuilderAbstract
return $this->grammar->compileQuery($this); return $this->grammar->compileQuery($this);
} }
/**
* Parsing to prepared string.
*
* @return string
*
* @since 1.0.0
*/
public function toPrepared() : string
{
return $this->grammar->compilePreparedQuery($this);
}
/** /**
* Set raw query. * Set raw query.
* *
@ -435,7 +423,7 @@ final class Builder extends BuilderAbstract
/** /**
* From. * From.
* *
* @param string|array ...$tables Tables * @param array ...$tables Tables
* *
* @return Builder * @return Builder
* *
@ -486,7 +474,7 @@ final class Builder extends BuilderAbstract
*/ */
public function where($columns, $operator = null, $values = null, $boolean = 'and') : Builder public function where($columns, $operator = null, $values = null, $boolean = 'and') : Builder
{ {
if ($operator !== null && !\is_array($operator) && !\in_array(strtolower($operator), self::OPERATORS)) { if ($operator !== null && !\is_array($operator) && !\in_array(\strtolower($operator), self::OPERATORS)) {
throw new \InvalidArgumentException('Unknown operator.'); throw new \InvalidArgumentException('Unknown operator.');
} }
@ -499,7 +487,7 @@ final class Builder extends BuilderAbstract
$i = 0; $i = 0;
foreach ($columns as $key => $column) { foreach ($columns as $key => $column) {
if (isset($operator[$i]) && !\in_array(strtolower($operator[$i]), self::OPERATORS)) { if (isset($operator[$i]) && !\in_array(\strtolower($operator[$i]), self::OPERATORS)) {
throw new \InvalidArgumentException('Unknown operator.'); throw new \InvalidArgumentException('Unknown operator.');
} }
@ -1214,9 +1202,9 @@ final class Builder extends BuilderAbstract
*/ */
public static function getBindParamType($value) public static function getBindParamType($value)
{ {
if (is_int($value)) { if (\is_int($value)) {
return \PDO::PARAM_INT; return \PDO::PARAM_INT;
} elseif (\is_string($value) || is_float($value)) { } elseif (\is_string($value) || \is_float($value)) {
return \PDO::PARAM_STR; return \PDO::PARAM_STR;
} }
@ -1239,7 +1227,7 @@ final class Builder extends BuilderAbstract
if (\is_string($column)) { if (\is_string($column)) {
return $column; return $column;
} elseif ($column instanceof Column) { } elseif ($column instanceof Column) {
return $column->getPublicName(); return $column->getColumn();
} elseif ($column instanceof \Closure) { } elseif ($column instanceof \Closure) {
return $column(); return $column();
} elseif ($column instanceof \Serializable) { } elseif ($column instanceof \Serializable) {

View File

@ -284,7 +284,12 @@ class Grammar extends GrammarAbstract
$expression = ' ' . \strtoupper($element['boolean']) . ' '; $expression = ' ' . \strtoupper($element['boolean']) . ' ';
} }
if (is_string($element['column'])) { if (\is_string($element['column'])) {
// 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'], $query->getPrefix()); $expression .= $this->compileSystem($element['column'], $query->getPrefix());
} elseif ($element['column'] instanceof \Closure) { } elseif ($element['column'] instanceof \Closure) {
$expression .= $element['column'](); $expression .= $element['column']();
@ -327,15 +332,15 @@ class Grammar extends GrammarAbstract
*/ */
protected function compileValue(Builder $query, $value, string $prefix = '') : string protected function compileValue(Builder $query, $value, string $prefix = '') : string
{ {
if (is_string($value)) { if (\is_string($value)) {
if (strpos($value, ':') === 0) { if (\strpos($value, ':') === 0) {
return $value; return $value;
} }
return $query->quote($value); return $query->quote($value);
} elseif (is_int($value)) { } elseif (\is_int($value)) {
return (string) $value; return (string) $value;
} elseif (is_array($value)) { } elseif (\is_array($value)) {
$values = ''; $values = '';
foreach ($value as $val) { foreach ($value as $val) {
@ -347,9 +352,9 @@ class Grammar extends GrammarAbstract
return $query->quote($value->format('Y-m-d H:i:s')); return $query->quote($value->format('Y-m-d H:i:s'));
} elseif ($value === null) { } elseif ($value === null) {
return 'NULL'; return 'NULL';
} elseif (is_bool($value)) { } elseif (\is_bool($value)) {
return (string) ((int) $value); return (string) ((int) $value);
} elseif (is_float($value)) { } elseif (\is_float($value)) {
return (string) $value; return (string) $value;
} elseif ($value instanceof Column) { } elseif ($value instanceof Column) {
return $this->compileSystem($value->getColumn(), $prefix); return $this->compileSystem($value->getColumn(), $prefix);

View File

@ -24,7 +24,7 @@ use phpOMS\DataStorage\Database\Query\Builder;
* @link http://website.orange-management.de * @link http://website.orange-management.de
* @since 1.0.0 * @since 1.0.0
*/ */
class SqliteGrammar extends Grammar class SQLiteGrammar extends Grammar
{ {
/** /**

View File

@ -32,5 +32,5 @@ abstract class QueryType extends Enum
public const DELETE = 3; public const DELETE = 3;
public const RANDOM = 4; public const RANDOM = 4;
public const RAW = 5; public const RAW = 5;
public const EMPTY = 6; public const NONE = 6;
} }

View File

@ -49,18 +49,20 @@ class TableException extends \PDOException
*/ */
public static function findTable(string $message) : string public static function findTable(string $message) : string
{ {
$pos1 = strpos($message, '\''); $pos1 = \strpos($message, '\'');
if ($pos1 === false) { if ($pos1 === false) {
return $message; return $message;
} }
$pos2 = strpos($message, '\'', $pos1 + 1); $pos2 = \strpos($message, '\'', $pos1 + 1);
if ($pos2 === false) { if ($pos2 === false) {
return $message; return $message;
} }
return substr($message, $pos1 + 1, $pos2 - $pos1 - 1); $table = \substr($message, $pos1 + 1, $pos2 - $pos1 - 1);
return $table === false ? $message : $table;
} }
} }

View File

@ -67,7 +67,7 @@ class MysqlGrammar extends Grammar
*/ */
protected function compileFrom(Builder $query, array $table) : string protected function compileFrom(Builder $query, array $table) : string
{ {
$expression = $this->expressionizeTableColumn('information_schema.tables'); $expression = $this->expressionizeTableColumn(['information_schema.tables']);
return 'FROM ' . $expression; return 'FROM ' . $expression;
} }

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Schema\Grammar; namespace phpOMS\DataStorage\Database\Schema\Grammar;
class PostgresGrammar class PostgresGrammar extends Grammar
{ {
} }

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database\Schema\Grammar; namespace phpOMS\DataStorage\Database\Schema\Grammar;
class SQLiteGrammar class SQLiteGrammar extends Grammar
{ {
} }

View File

@ -50,7 +50,7 @@ class HttpSession implements SessionInterface
/** /**
* Session ID. * Session ID.
* *
* @var string|int * @var string|int|null
* @since 1.0.0 * @since 1.0.0
*/ */
private $sid = null; private $sid = null;
@ -85,7 +85,7 @@ class HttpSession implements SessionInterface
} }
if (!\is_bool($sid)) { if (!\is_bool($sid)) {
\session_id($sid); \session_id((string) $sid);
} }
$this->inactivityInterval = $inactivityInterval; $this->inactivityInterval = $inactivityInterval;

View File

@ -74,14 +74,14 @@ interface SessionInterface
public function save() : void; public function save() : void;
/** /**
* @return int|string * @return int|string|null
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function getSID(); public function getSID();
/** /**
* @param int|string $sid Session id * @param int|string|null $sid Session id
* *
* @return void * @return void
* *

View File

@ -63,7 +63,7 @@ final class Dispatcher
* Dispatch controller. * Dispatch controller.
* *
* @param string|array|\Closure $controller Controller string * @param string|array|\Closure $controller Controller string
* @param array|null ...$data Data * @param array|null|mixed ...$data Data
* *
* @return array * @return array
* *
@ -111,7 +111,12 @@ final class Dispatcher
if (($c = count($dispatch)) === 3) { if (($c = count($dispatch)) === 3) {
/* Handling static functions */ /* Handling static functions */
$function = $dispatch[0] . '::' . $dispatch[2]; $function = $dispatch[0] . '::' . $dispatch[2];
if (!\is_callable($function)) {
throw new \Exception();
}
$views[$controller] = $function(...$data); $views[$controller] = $function(...$data);
} elseif ($c === 2) { } elseif ($c === 2) {
$this->getController($dispatch[0]); $this->getController($dispatch[0]);
@ -135,9 +140,14 @@ final class Dispatcher
*/ */
private function dispatchArray(array $controller, array $data = null) : array private function dispatchArray(array $controller, array $data = null) : array
{ {
$views = []; $views = [];
foreach ($controller as $controllerSingle) { foreach ($controller as $controllerSingle) {
$views += $this->dispatch($controllerSingle, ...$data); if ($data === null) {
$views += $this->dispatch($controllerSingle);
} else {
$views += $this->dispatch($controllerSingle, ...$data);
}
} }
return $views; return $views;

View File

@ -162,7 +162,10 @@ final class EventManager
*/ */
public function detach(string $group) : bool public function detach(string $group) : bool
{ {
return $this->detachCallback($group) || $this->detachGroup($group); $result1 = $this->detachCallback($group);
$result2 = $this->detachGroup($group);
return $result1 || $result2;
} }
/** /**

View File

@ -1,6 +1,6 @@
{ {
"language": "EN", "language": "en",
"country": "USA", "country": "US",
"currency": { "currency": {
"code": "USD", "code": "USD",
"position": 0 "position": 0

View File

@ -43,7 +43,7 @@ final class Iban
/** /**
* Iban chars. * Iban chars.
* *
* @var string * @var int
* @since 1.0.0 * @since 1.0.0
*/ */
private $chars = 2; private $chars = 2;

View File

@ -106,7 +106,7 @@ final class L11nManager
public function loadLanguageFromFile(string $language, string $from, string $file) : void public function loadLanguageFromFile(string $language, string $from, string $file) : void
{ {
$lang = []; $lang = [];
if (file_exists($file)) { if (\file_exists($file)) {
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$lang = include $file; $lang = include $file;
} }
@ -158,7 +158,7 @@ final class L11nManager
if (!isset($this->language[$code][$module][$translation])) { if (!isset($this->language[$code][$module][$translation])) {
return 'ERROR'; return 'ERROR';
} }
} catch (\Exception $e) { } catch (\Throwable $e) {
FileLogger::getInstance()->warning(FileLogger::MSG_FULL, [ FileLogger::getInstance()->warning(FileLogger::MSG_FULL, [
'message' => 'Undefined translation for \'' . $code . '/' . $module . '/' . $translation . '\'.', 'message' => 'Undefined translation for \'' . $code . '/' . $module . '/' . $translation . '\'.',
]); ]);
@ -184,6 +184,6 @@ final class L11nManager
*/ */
public function getHtml(string $code, string $module, string $theme, $translation) : string public function getHtml(string $code, string $module, string $theme, $translation) : string
{ {
return htmlspecialchars($this->getText($code, $module, $theme, $translation)); return \htmlspecialchars($this->getText($code, $module, $theme, $translation));
} }
} }

View File

@ -17,6 +17,7 @@ namespace phpOMS\Localization;
use phpOMS\Stdlib\Base\Exception\InvalidEnumValue; use phpOMS\Stdlib\Base\Exception\InvalidEnumValue;
use phpOMS\Utils\Converter\AngleType; use phpOMS\Utils\Converter\AngleType;
use phpOMS\Utils\Converter\TemperatureType; use phpOMS\Utils\Converter\TemperatureType;
use phpOMS\System\File\Local\Directory;
/** /**
* Localization class. * Localization class.
@ -91,10 +92,10 @@ final class Localization
/** /**
* Time format. * Time format.
* *
* @var string * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
private $datetime = 'Y-m-d H:i:s'; private $datetime = [];
/** /**
* Weight. * Weight.
@ -137,12 +138,68 @@ final class Localization
private $volume = []; private $volume = [];
/** /**
* Constructor. * Load localization from language code
*
* @param string $langCode Language code
*
* @return void
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function __construct() public function loadFromLanguage(string $langCode) : void
{ {
$langCode = \strtolower($langCode);
if (!ISO639x1Enum::isValidValue($langCode)) {
throw new InvalidEnumValue($langCode);
}
$files = Directory::list(__DIR__ . '/../Localization/Defaults/Definitions');
foreach ($files as $file) {
if (\stripos($file, $langCode) === 0) {
$this->importLocale(
json_decode(
\file_get_contents(__DIR__ . '/../Localization/Defaults/Definitions/' . $file),
true
)
);
return;
}
}
$this->importLocale(
json_decode(
\file_get_contents(__DIR__ . '/../Localization/Defaults/Definitions/en_US.json'),
true
)
);
}
/**
* Load localization from locale
*
* @param array $locale Locale data
*
* @return void
*
* @since 1.0.0
*/
public function importLocale(array $locale) : void
{
$this->setLanguage($locale['language'] ?? 'en');
$this->setCountry($locale['country'] ?? 'US');
$this->setCurrency($locale['currency']['code'] ?? ISO4217Enum::_USD);
$this->setThousands($locale['thousand'] ?? ',');
$this->setDecimal($locale['decimal'] ?? '.');
$this->setAngle($locale['angle'] ?? AngleType::DEGREE);
$this->setTemperature($locale['temperature'] ?? emperatureType::CELSIUS);
$this->setWeight($locale['weight'] ?? []);
$this->setSpeed($locale['speed'] ?? []);
$this->setLength($locale['length'] ?? []);
$this->setArea($locale['area'] ?? []);
$this->setVolume($locale['volume'] ?? []);
$this->setDatetime($locale['datetime'] ?? []);
} }
/** /**
@ -264,7 +321,7 @@ final class Localization
*/ */
public function setCurrency(string $currency) : void public function setCurrency(string $currency) : void
{ {
if (!ISO4217Enum::isValidValue($currency)) { if (!ISO4217CharEnum::isValidValue($currency)) {
throw new InvalidEnumValue($currency); throw new InvalidEnumValue($currency);
} }
@ -274,11 +331,11 @@ final class Localization
/** /**
* get datetime format * get datetime format
* *
* @return string * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function getDatetime() : string public function getDatetime() : array
{ {
return $this->datetime; return $this->datetime;
} }
@ -286,13 +343,13 @@ final class Localization
/** /**
* Set datetime format * Set datetime format
* *
* @param string $datetime Datetime format * @param array $datetime Datetime format
* *
* @return void * @return void
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function setDatetime(string $datetime) : void public function setDatetime(array $datetime) : void
{ {
$this->datetime = $datetime; $this->datetime = $datetime;
} }

View File

@ -107,6 +107,11 @@ final class Money implements \Serializable
public static function toInt(string $value, string $thousands = ',', string $decimal = '.') : int public static function toInt(string $value, string $thousands = ',', string $decimal = '.') : int
{ {
$split = \explode($decimal, $value); $split = \explode($decimal, $value);
if ($split === false) {
throw new \Exception();
}
$left = $split[0]; $left = $split[0];
$left = \str_replace($thousands, '', $left); $left = \str_replace($thousands, '', $left);
$right = ''; $right = '';
@ -116,6 +121,9 @@ final class Money implements \Serializable
} }
$right = \substr($right, 0, self::MAX_DECIMALS); $right = \substr($right, 0, self::MAX_DECIMALS);
if ($right === false) {
throw new \Exception();
}
return ((int) $left) * 10 ** self::MAX_DECIMALS + (int) \str_pad($right, self::MAX_DECIMALS, '0'); return ((int) $left) * 10 ** self::MAX_DECIMALS + (int) \str_pad($right, self::MAX_DECIMALS, '0');
} }
@ -187,8 +195,11 @@ final class Money implements \Serializable
$left = \substr($value, 0, -self::MAX_DECIMALS); $left = \substr($value, 0, -self::MAX_DECIMALS);
$right = \substr($value, -self::MAX_DECIMALS); $right = \substr($value, -self::MAX_DECIMALS);
if ($left === false || $right === false) {
throw new \Exception();
}
return ($decimals > 0) ? number_format((float) $left, 0, $this->decimal, $this->thousands) . $this->decimal . \substr($right, 0, $decimals) : (string) $left; return ($decimals > 0) ? number_format((float) $left, 0, $this->decimal, $this->thousands) . $this->decimal . \substr($right, 0, $decimals) : $left;
} }
/** /**
@ -309,7 +320,7 @@ final class Money implements \Serializable
public function pow($value) : Money public function pow($value) : Money
{ {
if (is_float($value) || is_int($value)) { if (is_float($value) || is_int($value)) {
$this->value = $this->value ** $value; $this->value = (int) ($this->value ** $value);
} }
return $this; return $this;

View File

@ -98,11 +98,11 @@ final class FileLogger implements LoggerInterface
*/ */
public function __construct(string $lpath, bool $verbose = false) public function __construct(string $lpath, bool $verbose = false)
{ {
$path = realpath($lpath); $path = \realpath($lpath);
$this->verbose = $verbose; $this->verbose = $verbose;
if (is_dir($lpath) || strpos($lpath, '.') === false) { if (\is_dir($lpath) || \strpos($lpath, '.') === false) {
$path = $lpath . '/' . date('Y-m-d') . '.log'; $path = $lpath . '/' . \date('Y-m-d') . '.log';
} else { } else {
$path = $lpath; $path = $lpath;
} }
@ -154,8 +154,8 @@ final class FileLogger implements LoggerInterface
*/ */
public function __destruct() public function __destruct()
{ {
if (is_resource($this->fp)) { if (\is_resource($this->fp)) {
fclose($this->fp); \fclose($this->fp);
} }
} }
@ -186,8 +186,8 @@ final class FileLogger implements LoggerInterface
return false; return false;
} }
$mtime = \explode(' ', microtime()); $temp = \explode(' ', \microtime());
$mtime = $mtime[1] + $mtime[0]; $mtime = ((float) $temp[1]) + ((float) $temp[0]);
self::$timings[$id] = ['start' => $mtime]; self::$timings[$id] = ['start' => $mtime];
@ -205,8 +205,8 @@ final class FileLogger implements LoggerInterface
*/ */
public static function endTimeLog($id = '') : float public static function endTimeLog($id = '') : float
{ {
$mtime = \explode(' ', microtime()); $temp = \explode(' ', \microtime());
$mtime = $mtime[1] + $mtime[0]; $mtime = ((float) $temp[1]) + ((float) $temp[0]);
self::$timings[$id]['end'] = $mtime; self::$timings[$id]['end'] = $mtime;
self::$timings[$id]['time'] = $mtime - self::$timings[$id]['start']; self::$timings[$id]['time'] = $mtime - self::$timings[$id]['start'];
@ -232,7 +232,7 @@ final class FileLogger implements LoggerInterface
$replace['{' . $key . '}'] = $val; $replace['{' . $key . '}'] = $val;
} }
$backtrace = debug_backtrace(); $backtrace = \debug_backtrace();
// Removing sensitive config data from logging // Removing sensitive config data from logging
foreach ($backtrace as $key => $value) { foreach ($backtrace as $key => $value) {
@ -244,15 +244,15 @@ final class FileLogger implements LoggerInterface
$backtrace = \json_encode($backtrace); $backtrace = \json_encode($backtrace);
$replace['{backtrace}'] = $backtrace; $replace['{backtrace}'] = $backtrace;
$replace['{datetime}'] = sprintf('%--19s', (new \DateTime('NOW'))->format('Y-m-d H:i:s')); $replace['{datetime}'] = \sprintf('%--19s', (new \DateTime('NOW'))->format('Y-m-d H:i:s'));
$replace['{level}'] = sprintf('%--12s', $level); $replace['{level}'] = \sprintf('%--12s', $level);
$replace['{path}'] = $_SERVER['REQUEST_URI'] ?? 'REQUEST_URI'; $replace['{path}'] = $_SERVER['REQUEST_URI'] ?? 'REQUEST_URI';
$replace['{ip}'] = sprintf('%--15s', $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'); $replace['{ip}'] = \sprintf('%--15s', $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0');
$replace['{version}'] = sprintf('%--15s', PHP_VERSION); $replace['{version}'] = \sprintf('%--15s', PHP_VERSION);
$replace['{os}'] = sprintf('%--15s', PHP_OS); $replace['{os}'] = \sprintf('%--15s', PHP_OS);
$replace['{line}'] = sprintf('%--15s', $context['line'] ?? '?'); $replace['{line}'] = \sprintf('%--15s', $context['line'] ?? '?');
return strtr($message, $replace); return \strtr($message, $replace);
} }
/** /**
@ -266,24 +266,24 @@ final class FileLogger implements LoggerInterface
*/ */
private function write(string $message) : void private function write(string $message) : void
{ {
if ($this->verbose) {
echo $message, "\n";
}
$this->createFile(); $this->createFile();
if (!is_writable($this->path)) { if (!\is_writable($this->path)) {
return; return;
} }
$this->fp = fopen($this->path, 'a'); $this->fp = \fopen($this->path, 'a');
if (flock($this->fp, LOCK_EX) && $this->fp !== false) { if ($this->fp !== false && \flock($this->fp, LOCK_EX)) {
fwrite($this->fp, $message . "\n"); \fwrite($this->fp, $message . "\n");
fflush($this->fp); \fflush($this->fp);
flock($this->fp, LOCK_UN); \flock($this->fp, LOCK_UN);
fclose($this->fp); \fclose($this->fp);
$this->fp = false; $this->fp = false;
} }
if ($this->verbose) {
echo $message, "\n";
}
} }
/** /**
@ -386,21 +386,32 @@ final class FileLogger implements LoggerInterface
return $levels; return $levels;
} }
$this->fp = fopen($this->path, 'r'); $this->fp = \fopen($this->path, 'r');
fseek($this->fp, 0);
while (($line = fgetcsv($this->fp, 0, ';')) !== false) { if ($this->fp === false) {
$line[1] = trim($line[1]); return $levels;
}
\fseek($this->fp, 0);
$line = \fgetcsv($this->fp, 0, ';');
while ($line !== false && $line !== null) {
if (count($line) < 2) {
continue;
}
$line[1] = \trim($line[1]);
if (!isset($levels[$line[1]])) { if (!isset($levels[$line[1]])) {
$levels[$line[1]] = 0; $levels[$line[1]] = 0;
} }
$levels[$line[1]]++; $levels[$line[1]]++;
$line = \fgetcsv($this->fp, 0, ';');
} }
fseek($this->fp, 0, SEEK_END); \fseek($this->fp, 0, SEEK_END);
fclose($this->fp); \fclose($this->fp);
return $levels; return $levels;
} }
@ -422,24 +433,35 @@ final class FileLogger implements LoggerInterface
return $connection; return $connection;
} }
$this->fp = fopen($this->path, 'r'); $this->fp = \fopen($this->path, 'r');
fseek($this->fp, 0);
while (($line = fgetcsv($this->fp, 0, ';')) !== false) { if ($this->fp === false) {
$line[2] = trim($line[2]); return $connection;
}
\fseek($this->fp, 0);
$line = \fgetcsv($this->fp, 0, ';');
while ($line !== false && $line !== null) {
if (count($line) < 3) {
continue;
}
$line[2] = \trim($line[2]);
if (!isset($connection[$line[2]])) { if (!isset($connection[$line[2]])) {
$connection[$line[2]] = 0; $connection[$line[2]] = 0;
} }
$connection[$line[2]]++; $connection[$line[2]]++;
$line = \fgetcsv($this->fp, 0, ';');
} }
fseek($this->fp, 0, SEEK_END); \fseek($this->fp, 0, SEEK_END);
fclose($this->fp); \fclose($this->fp);
asort($connection); \asort($connection);
return array_slice($connection, 0, $limit); return \array_slice($connection, 0, $limit);
} }
/** /**
@ -461,10 +483,16 @@ final class FileLogger implements LoggerInterface
return $logs; return $logs;
} }
$this->fp = fopen($this->path, 'r'); $this->fp = \fopen($this->path, 'r');
fseek($this->fp, 0);
while (($line = fgetcsv($this->fp, 0, ';')) !== false) { if ($this->fp === false) {
return $logs;
}
\fseek($this->fp, 0);
$line = \fgetcsv($this->fp, 0, ';');
while ($line !== false && $line !== null) {
$id++; $id++;
if ($offset > 0) { if ($offset > 0) {
@ -478,16 +506,17 @@ final class FileLogger implements LoggerInterface
} }
foreach ($line as &$value) { foreach ($line as &$value) {
$value = trim($value); $value = \trim($value);
} }
$logs[$id] = $line; $logs[$id] = $line;
$limit--; $limit--;
ksort($logs); ksort($logs);
$line = \fgetcsv($this->fp, 0, ';');
} }
fseek($this->fp, 0, SEEK_END); \fseek($this->fp, 0, SEEK_END);
fclose($this->fp); \fclose($this->fp);
return $logs; return $logs;
} }
@ -510,31 +539,36 @@ final class FileLogger implements LoggerInterface
return $log; return $log;
} }
$this->fp = fopen($this->path, 'r'); $this->fp = \fopen($this->path, 'r');
fseek($this->fp, 0);
while (($line = fgetcsv($this->fp, 0, ';')) !== false && $current <= $id) { if ($this->fp === false) {
return $log;
}
\fseek($this->fp, 0);
while (($line = \fgetcsv($this->fp, 0, ';')) !== false && $current <= $id) {
$current++; $current++;
if ($current < $id) { if ($current < $id) {
continue; continue;
} }
$log['datetime'] = trim($line[0] ?? ''); $log['datetime'] = \trim($line[0] ?? '');
$log['level'] = trim($line[1] ?? ''); $log['level'] = \trim($line[1] ?? '');
$log['ip'] = trim($line[2] ?? ''); $log['ip'] = \trim($line[2] ?? '');
$log['line'] = trim($line[3] ?? ''); $log['line'] = \trim($line[3] ?? '');
$log['version'] = trim($line[4] ?? ''); $log['version'] = \trim($line[4] ?? '');
$log['os'] = trim($line[5] ?? ''); $log['os'] = \trim($line[5] ?? '');
$log['path'] = trim($line[6] ?? ''); $log['path'] = \trim($line[6] ?? '');
$log['message'] = trim($line[7] ?? ''); $log['message'] = \trim($line[7] ?? '');
$log['file'] = trim($line[8] ?? ''); $log['file'] = \trim($line[8] ?? '');
$log['backtrace'] = trim($line[9] ?? ''); $log['backtrace'] = \trim($line[9] ?? '');
break; break;
} }
fseek($this->fp, 0, SEEK_END); \fseek($this->fp, 0, SEEK_END);
fclose($this->fp); \fclose($this->fp);
return $log; return $log;
} }
@ -553,11 +587,11 @@ final class FileLogger implements LoggerInterface
public function console(string $message, bool $verbose = true, array $context = []) : void public function console(string $message, bool $verbose = true, array $context = []) : void
{ {
if (empty($context)) { if (empty($context)) {
$message = date('[Y-m-d H:i:s] ') . $message . "\r\n"; $message = \date('[Y-m-d H:i:s] ') . $message . "\r\n";
} }
if ($verbose) { if ($verbose) {
echo $message; echo $this->interpolate($message, $context);
} else { } else {
$this->info($message, $context); $this->info($message, $context);
} }

View File

@ -28,8 +28,8 @@ interface LoggerInterface
/** /**
* System is unusable. * System is unusable.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -41,8 +41,8 @@ interface LoggerInterface
* Example: Entire website down, database unavailable, etc. This should * Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up. * trigger the SMS alerts and wake you up.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -53,8 +53,8 @@ interface LoggerInterface
* *
* Example: Application component unavailable, unexpected exception. * Example: Application component unavailable, unexpected exception.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -64,8 +64,8 @@ interface LoggerInterface
* Runtime errors that do not require immediate action but should typically * Runtime errors that do not require immediate action but should typically
* be logged and monitored. * be logged and monitored.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -77,8 +77,8 @@ interface LoggerInterface
* Example: Use of deprecated APIs, poor use of an API, undesirable things * Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong. * that are not necessarily wrong.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -87,8 +87,8 @@ interface LoggerInterface
/** /**
* Normal but significant events. * Normal but significant events.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -99,8 +99,8 @@ interface LoggerInterface
* *
* Example: User logs in, SQL logs. * Example: User logs in, SQL logs.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -109,8 +109,8 @@ interface LoggerInterface
/** /**
* Detailed debug information. * Detailed debug information.
* *
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */
@ -119,9 +119,9 @@ interface LoggerInterface
/** /**
* Logs with an arbitrary level. * Logs with an arbitrary level.
* *
* @param string $level Log level/severeness * @param string $level Log level/severeness
* @param string $message Logging message schema * @param string $message Logging message schema
* @param array<string, string> $context Context to log * @param array<string, mixed> $context Context to log
* *
* @return void * @return void
*/ */

View File

@ -27,13 +27,12 @@ final class ZeroDevisionException extends \UnexpectedValueException
/** /**
* Constructor. * Constructor.
* *
* @param string $message Exception message
* @param int $code Exception code * @param int $code Exception code
* @param \Exception $previous Previous exception * @param \Exception $previous Previous exception
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function __construct(string $message = '', int $code = 0, \Exception $previous = null) public function __construct(int $code = 0, \Exception $previous = null)
{ {
parent::__construct('Devision by zero is not defined.', $code, $previous); parent::__construct('Devision by zero is not defined.', $code, $previous);
} }

View File

@ -315,6 +315,6 @@ final class Functions
*/ */
public static function getRelativeDegree(int $value, int $length, int $start = 0) : int public static function getRelativeDegree(int $value, int $length, int $start = 0) : int
{ {
return (int) abs(self::mod($value - $start, $length)); return abs(self::mod($value - $start, $length));
} }
} }

View File

@ -192,7 +192,7 @@ final class Polygon implements D2ShapeInterface
*/ */
public function getSurface() : float public function getSurface() : float
{ {
return (float) abs($this->getSignedSurface()); return abs($this->getSignedSurface());
} }
/** /**

View File

@ -116,7 +116,7 @@ final class Sphere implements D3ShapeInterface
*/ */
public static function getRadiusByVolume(float $v) : float public static function getRadiusByVolume(float $v) : float
{ {
return (float) pow($v * 3 / (4 * pi()), 1 / 3); return pow($v * 3 / (4 * pi()), 1 / 3);
} }
/** /**

View File

@ -402,7 +402,7 @@ class Matrix implements \ArrayAccess, \Iterator
{ {
if ($value instanceof Matrix) { if ($value instanceof Matrix) {
return $this->add($value->mult(-1)); return $this->add($value->mult(-1));
} elseif (is_numeric($value)) { } elseif (!is_string($value) && is_numeric($value)) {
return $this->add(-$value); return $this->add(-$value);
} }
@ -424,7 +424,7 @@ class Matrix implements \ArrayAccess, \Iterator
{ {
if ($value instanceof Matrix) { if ($value instanceof Matrix) {
return $this->addMatrix($value); return $this->addMatrix($value);
} elseif (is_numeric($value)) { } elseif (!is_string($value) && is_numeric($value)) {
return $this->addScalar($value); return $this->addScalar($value);
} }
@ -529,7 +529,7 @@ class Matrix implements \ArrayAccess, \Iterator
{ {
if ($value instanceof Matrix) { if ($value instanceof Matrix) {
return $this->multMatrix($value); return $this->multMatrix($value);
} elseif (is_numeric($value)) { } elseif (!is_string($value) && is_numeric($value)) {
return $this->multScalar($value); return $this->multScalar($value);
} }

View File

@ -159,7 +159,7 @@ final class Complex
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
public function powComplex() : Complex public function powComplex(Complex $value) : Complex
{ {
} }
@ -184,7 +184,7 @@ final class Complex
return $this->multComplex($this->powInteger(--$value)); return $this->multComplex($this->powInteger(--$value));
} }
public function powScalar() : Complex public function powScalar($value) : Complex
{ {
} }

View File

@ -138,7 +138,7 @@ final class Integer
} }
} }
return (int) $m; return $m;
} }
/** /**
@ -160,13 +160,13 @@ final class Integer
} }
$a = (int) ceil(sqrt($value)); $a = (int) ceil(sqrt($value));
$b2 = (int) ($a * $a - $value); $b2 = ($a * $a - $value);
$i = 1; $i = 1;
while (!Numbers::isSquare($b2) && $i < $limit) { while (!Numbers::isSquare($b2) && $i < $limit) {
$i++; $i++;
$a += 1; $a += 1;
$b2 = (int) ($a * $a - $value); $b2 = ($a * $a - $value);
} }
return [(int) round($a - sqrt($b2)), (int) round($a + sqrt($b2))]; return [(int) round($a - sqrt($b2)), (int) round($a + sqrt($b2))];

View File

@ -69,10 +69,14 @@ final class Numbers
public static function isSelfdescribing(int $n) : bool public static function isSelfdescribing(int $n) : bool
{ {
$n = (string) $n; $n = (string) $n;
$split = str_split($n); $split = \str_split($n);
if ($split === false) {
return false;
}
foreach ($split as $place => $value) { foreach ($split as $place => $value) {
if (substr_count($n, (string) $place) != $value) { if (\substr_count($n, (string) $place) != $value) {
return false; return false;
} }
} }

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
namespace phpOMS\Math\Parser; namespace phpOMS\Math\Parser;
/** /**
* Shape interface. * Basic math function evaluation.
* *
* @package Framework * @package Framework
* @license OMS License 1.0 * @license OMS License 1.0
@ -27,10 +27,7 @@ class Evaluator
/** /**
* Evaluate function. * Evaluate function.
* *
* Example: ('2*x^3-4x', ['x' => 99]) * @param string $equation Formula to evaluate
*
* @param string $formula Formula to differentiate
* @param array $vars Variables to evaluate
* *
* @return float * @return float
* *
@ -38,18 +35,118 @@ class Evaluator
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function evaluate(string $formula, array $vars) : float public static function evaluate(string $equation) : ?float
{ {
// todo: do i need array_values here? if (\preg_match('#[^0-9\+\-\*\/\(\)\ \^\.]#', $equation)) {
$formula = \str_replace(array_keys($vars), array_values($vars), $formula); return null;
// todo: this is horrible in case things like mod etc. need to be supported
if (\preg_match('#[^0-9\+\-\*\/\(\)]#', $formula)) {
throw new \Exception('Bad elements');
} }
// todo: create parser $stack = [];
$postfix = self::shuntingYard($equation);
return 0; foreach ($postfix as $i => $value) {
if (\is_numeric($value)) {
$stack[] = $value;
} else {
$a = self::parseValue(\array_pop($stack));
$b = self::parseValue(\array_pop($stack));
if ($value === '+') {
$stack[] = $a + $b;
} elseif ($value === '-') {
$stack[] = $b - $a;
} elseif ($value === '*') {
$stack[] = $a * $b;
} elseif ($value === '/') {
$stack[] = $b / $a;
} elseif ($value === '^') {
$stack[] = $b ** $a;
}
}
}
$result = \array_pop($stack);
return \is_numeric($result) ? (float) $result : null;
}
/**
* Parse value.
*
* @param mixed $value Value to parse
*
* @return mixed
*
* @since 1.0.0
*/
private static function parseValue($value)
{
return !\is_string($value) ? $value : (\stripos($value, '.') === false ? (int) $value : (float) $value);
}
/**
* Shunting Yard algorithm.
*
* @param string $equation Equation to convert
*
* @return array
*
* @since 1.0.0
*/
private static function shuntingYard(string $equation) : array
{
$stack = [];
$operators = [
'^' => ['precedence' => 4, 'order' => 1],
'*' => ['precedence' => 3, 'order' => -1],
'/' => ['precedence' => 3, 'order' => -1],
'+' => ['precedence' => 2, 'order' => -1],
'-' => ['precedence' => 2, 'order' => -1],
];
$output = [];
$equation = \str_replace(' ', '', $equation);
$equation = \preg_split('/([\+\-\*\/\^\(\)])/', $equation, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
if ($equation === false) {
return [];
}
$equation = \array_filter($equation, function($n) {
return $n !== '';
});
foreach ($equation as $i => $token) {
if (\is_numeric($token)) {
$output[] = $token;
} elseif (\strpbrk($token, '^*/+-') !== false) {
$o1 = $token;
$o2 = end($stack);
while ($o2 !== false && \strpbrk($o2, '^*/+-') !== false
&& (($operators[$o1]['order'] === -1 && $operators[$o1]['precedence'] <= $operators[$o2]['precedence'])
|| ($operators[$o1]['order'] === 1 && $operators[$o1]['precedence'] < $operators[$o2]['precedence']))
) {
$output[] = \array_pop($stack);
$o2 = end($stack);
}
$stack[] = $o1;
} elseif ($token === '(') {
$stack[] = $token;
} elseif ($token === ')') {
while (end($stack) !== '(') {
$output[] = \array_pop($stack);
}
\array_pop($stack);
}
}
while (count($stack) > 0) {
$output[] = \array_pop($stack);
}
return $output;
} }
} }

View File

@ -168,7 +168,7 @@ final class Average
* *
* @return float * @return float
* *
* @throws phpOMS\Math\Exception\ZeroDevisionException * @throws ZeroDevisionException
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@ -252,7 +252,7 @@ final class Average
throw new ZeroDevisionException(); throw new ZeroDevisionException();
} }
return (float) pow(array_product($values), 1 / $count); return pow(\array_product($values), 1 / $count);
} }
/** /**

View File

@ -57,7 +57,7 @@ class BinomialDistribution
*/ */
public static function getMgf(int $n, float $t, float $p) : float public static function getMgf(int $n, float $t, float $p) : float
{ {
return (float) pow(1 - $p + $p * exp($t), $n); return pow(1 - $p + $p * exp($t), $n);
} }
/** /**

View File

@ -31,7 +31,7 @@ class ChiSquaredDistribution
/** /**
* Chi square table. * Chi square table.
* *
* @var array * @var array<int, array<string, float>>
* @since 1.0.0 * @since 1.0.0
*/ */
public const TABLE = [ public const TABLE = [
@ -106,7 +106,7 @@ class ChiSquaredDistribution
$df = self::getDegreesOfFreedom($dataset); $df = self::getDegreesOfFreedom($dataset);
} }
if (!defined(self::TABLE[$df])) { if (!defined('self::TABLE') || !array_key_exists($df, self::TABLE)) {
throw new \Exception('Degrees of freedom not supported'); throw new \Exception('Degrees of freedom not supported');
} }
@ -117,7 +117,8 @@ class ChiSquaredDistribution
} }
} }
$p = 1 - ($p ?? key(end(self::TABLE[$df]))); $key = key(end(self::TABLE[$df]));
$p = 1 - ($p ?? ($key === false ? 1 : (float) $key));
return ['P' => $p, 'H0' => ($p > $significance), 'df' => $df]; return ['P' => $p, 'H0' => ($p > $significance), 'df' => $df];
} }
@ -235,7 +236,7 @@ class ChiSquaredDistribution
throw new \Exception('Out of bounds'); throw new \Exception('Out of bounds');
} }
return (float) pow(1 - 2 * $t, -$df / 2); return pow(1 - 2 * $t, -$df / 2);
} }
/** /**

View File

@ -105,7 +105,7 @@ class ExponentialDistribution
*/ */
public static function getVariance(float $lambda) : float public static function getVariance(float $lambda) : float
{ {
return (float) pow($lambda, -2); return pow($lambda, -2);
} }
/** /**

View File

@ -36,7 +36,7 @@ class GeometricDistribution
*/ */
public static function getPmf(float $p, int $k) : float public static function getPmf(float $p, int $k) : float
{ {
return (float) pow(1 - $p, $k - 1) * $p; return pow(1 - $p, $k - 1) * $p;
} }
/** /**

View File

@ -147,7 +147,7 @@ class PoissonDistribution
*/ */
public static function getSkewness(float $lambda) : float public static function getSkewness(float $lambda) : float
{ {
return (float) pow($lambda, -1 / 2); return pow($lambda, -1 / 2);
} }
/** /**
@ -161,7 +161,7 @@ class PoissonDistribution
*/ */
public static function getFisherInformation(float $lambda) : float public static function getFisherInformation(float $lambda) : float
{ {
return (float) pow($lambda, -1); return pow($lambda, -1);
} }
/** /**
@ -175,7 +175,7 @@ class PoissonDistribution
*/ */
public static function getExKurtosis(float $lambda) : float public static function getExKurtosis(float $lambda) : float
{ {
return (float) pow($lambda, -1); return pow($lambda, -1);
} }
public static function getRandom() public static function getRandom()

View File

@ -0,0 +1,270 @@
<?php
/**
* Orange Management
*
* PHP Version 7.2
*
* @package phpOMS\Message\Http
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link http://website.orange-management.de
*/
declare(strict_types=1);
namespace phpOMS\Message\Console;
use phpOMS\Message\HeaderAbstract;
use phpOMS\DataStorage\LockException;
/**
* Response class.
*
* @package phpOMS\Message\Http
* @license OMS License 1.0
* @link http://website.orange-management.de
* @since 1.0.0
*
* @SuppressWarnings(PHPMD.Superglobals)
*/
final class Header extends HeaderAbstract
{
/**
* Protocol version.
*
* @var string
* @since 1.0.0
*/
private const VERSION = '1.0';
/**
* Header.
*
* @var string[][]
* @since 1.0.0
*/
private $header = [];
/**
* Constructor.
*
* @since 1.0.0
*/
public function __construct()
{
$this->set('Content-Type', 'text/html; charset=utf-8');
parent::__construct();
}
/**
* Set header.
*
* @param string $key Header key (case insensitive)
* @param string $header Header value
* @param bool $overwrite Overwrite if already existing
*
* @return bool
*
* @since 1.0.0
*/
public function set(string $key, string $header, bool $overwrite = false) : bool
{
if (self::$isLocked) {
return false;
}
if (self::isSecurityHeader($key) && isset($this->header[$key])) {
return false;
}
$key = strtolower($key);
if (!$overwrite && isset($this->header[$key])) {
return false;
}
unset($this->header[$key]);
if (!isset($this->header[$key])) {
$this->header[$key] = [];
}
$this->header[$key][] = $header;
return true;
}
/**
* Is security header.
*
* @param string $key Header key
*
* @return bool
*
* @since 1.0.0
*/
public static function isSecurityHeader(string $key) : bool
{
$key = strtolower($key);
return $key === 'content-security-policy'
|| $key === 'x-xss-protection'
|| $key === 'x-content-type-options'
|| $key === 'x-frame-options';
}
/**
* {@inheritdoc}
*/
public function getProtocolVersion() : string
{
return self::VERSION;
}
/**
* Get status code.
*
* @return int
*
* @since 1.0.0
*/
public function getStatusCode() : int
{
if ($this->status === 0) {
$this->status = (int) \http_response_code();
}
return parent::getStatusCode();
}
/**
* Get all headers for apache and nginx
*
* @return array
*
* @since 1.0.0
*/
public static function getAllHeaders() : array
{
if (function_exists('getallheaders')) {
// @codeCoverageIgnoreStart
return getallheaders();
// @codeCoverageIgnoreEnd
}
$headers = [];
foreach ($_SERVER as $name => $value) {
$part = \substr($name, 5);
if ($part === 'HTTP_') {
$headers[\str_replace(' ', '-', \ucwords(\strtolower(\str_replace('_', ' ', $part))))] = $value;
}
}
return $headers;
}
/**
* Remove header by ID.
*
* @param mixed $key Header key
*
* @return bool
*
* @since 1.0.0
*/
public function remove($key) : bool
{
if (self::$isLocked) {
return false;
}
if (isset($this->header[$key])) {
unset($this->header[$key]);
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function getReasonPhrase() : string
{
$phrases = $this->get('Status');
return empty($phrases) ? '' : $phrases[0];
}
/**
* Get header by name.
*
* @param string $key Header key
*
* @return array
*
* @since 1.0.0
*/
public function get(string $key) : array
{
return $this->header[strtolower($key)] ?? [];
}
/**
* Check if header is defined.
*
* @param string $key Header key
*
* @return bool
*
* @since 1.0.0
*/
public function has(string $key) : bool
{
return isset($this->header[$key]);
}
/**
* Push all headers.
*
* @return void
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function push() : void
{
if (self::$isLocked) {
throw new \Exception('Already locked');
}
foreach ($this->header as $name => $arr) {
foreach ($arr as $ele => $value) {
header($name . ': ' . $value);
}
}
}
/**
* {@inheritdoc}
*/
public function generate(int $code) : void
{
switch ($code) {
default:
$this->generate500();
}
}
/**
* Generate predefined header.
*
* @return void
*
* @since 1.0.0
*/
private function generate500() : void
{
}
}

View File

@ -17,7 +17,9 @@ namespace phpOMS\Message\Console;
use phpOMS\Localization\Localization; use phpOMS\Localization\Localization;
use phpOMS\Message\RequestAbstract; use phpOMS\Message\RequestAbstract;
use phpOMS\Message\RequestSource; use phpOMS\Message\RequestSource;
use phpOMS\Message\Http\RequestMethod;
use phpOMS\Router\RouteVerb; use phpOMS\Router\RouteVerb;
use phpOMS\Uri\UriInterface;
/** /**
* Request class. * Request class.
@ -50,12 +52,39 @@ final class Request extends RequestAbstract
public function __construct(UriInterface $uri, Localization $l11n = null) public function __construct(UriInterface $uri, Localization $l11n = null)
{ {
$this->header = new Header(); $this->header = new Header();
$this->header->setL11n($l11n ?? new Localization());
if ($l11n === null) { $this->uri = $uri;
$l11n = $l11n ?? new Localization(); $this->init();
} }
$this->header->setL11n($l11n); /**
* Init request.
*
* This is used in order to either initialize the current http request or a batch of GET requests
*
* @return void
*
* @since 1.0.0
*/
private function init() : void
{
$lang = \explode('_', $_SERVER['LANG'] ?? '');
$this->header->getL11n()->setLanguage($lang[0] ?? 'en');
$this->cleanupGlobals();
}
/**
* Clean up globals that musn't be used any longer
*
* @return void
*
* @since 1.0.0
*/
private function cleanupGlobals() : void
{
unset($_SERVER);
} }
/** /**
@ -80,7 +109,7 @@ final class Request extends RequestAbstract
$paths[] = $pathArray[$i]; $paths[] = $pathArray[$i];
} }
$this->hash[] = sha1(implode('', $paths)); $this->hash[] = sha1(\implode('', $paths));
} }
} }
@ -115,7 +144,11 @@ final class Request extends RequestAbstract
public function getMethod() : string public function getMethod() : string
{ {
if ($this->method === null) { if ($this->method === null) {
$this->method = RequestMethod::GET; $temp = $this->uri->__toString();
$found = \stripos($temp, ':');
$method = $found !== false && $found > 3 && $found < 8 ? \substr($temp, 0, $found) : RequestMethod::GET;
$this->method = $method === false ? RequestMethod::GET : $method;
} }
return $this->method; return $this->method;

View File

@ -0,0 +1,174 @@
<?php
/**
* Orange Management
*
* PHP Version 7.2
*
* @package phpOMS\Message\Http
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link http://website.orange-management.de
*/
declare(strict_types=1);
namespace phpOMS\Message\Console;
use phpOMS\Contract\RenderableInterface;
use phpOMS\Localization\Localization;
use phpOMS\Message\ResponseAbstract;
use phpOMS\System\MimeType;
use phpOMS\Views\View;
use phpOMS\Message\Http\RequestStatusCode;
/**
* Response class.
*
* @package phpOMS\Message\Http
* @license OMS License 1.0
* @link http://website.orange-management.de
* @since 1.0.0
*/
final class Response extends ResponseAbstract implements RenderableInterface
{
/**
* Response status.
*
* @var int
* @since 1.0.0
*/
protected $status = RequestStatusCode::R_200;
/**
* Constructor.
*
* @param Localization $l11n Localization
*
* @since 1.0.0
*/
public function __construct(Localization $l11n = null)
{
$this->header = new Header();
$this->header->setL11n($l11n ?? new Localization());
}
/**
* Set response.
*
* @param array $response Response to set
*
* @return void
*
* @since 1.0.0
*/
public function setResponse(array $response) : void
{
$this->response = $response;
}
/**
* Remove response by ID.
*
* @param mixed $id Response ID
*
* @return bool
*
* @since 1.0.0
*/
public function remove($id) : bool
{
if (isset($this->response[$id])) {
unset($this->response[$id]);
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function getBody() : string
{
return $this->render();
}
/**
* Generate response based on header.
*
* @return string
*
* @since 1.0.0
*/
public function render() : string
{
$types = $this->header->get('Content-Type');
foreach ($types as $type) {
if (\stripos($type, MimeType::M_JSON) !== false) {
return (string) \json_encode($this->jsonSerialize());
}
}
return $this->getRaw();
}
/**
* Generate raw response.
*
* @return string
*
* @throws \Exception
*
* @since 1.0.0
*/
private function getRaw() : string
{
$render = '';
foreach ($this->response as $key => $response) {
if ($response instanceOf \Serializable) {
$render .= $response->serialize();
} elseif (\is_string($response) || \is_numeric($response)) {
$render .= $response;
} else {
throw new \Exception('Wrong response type');
}
}
return $render;
}
/**
* {@inheritdoc}
*/
public function toArray() : array
{
$result = [];
try {
foreach ($this->response as $key => $response) {
if ($response instanceof View) {
$result += $response->toArray();
} elseif (\is_array($response)) {
$result += $response;
} elseif (\is_scalar($response)) {
$result[] = $response;
} elseif ($response instanceof \JsonSerializable) {
$result[] = $response->jsonSerialize();
} elseif ($response === null) {
continue;
} else {
throw new \Exception('Wrong response type');
}
}
} catch (\Exception $e) {
// todo: handle exception
// need to to try catch for logging. otherwise the json_encode in the logger will have a problem with this
$result = [];
} finally {
return $result;
}
}
}

View File

@ -70,7 +70,7 @@ final class Header extends HeaderAbstract
return false; return false;
} }
$key = strtolower($key); $key = \strtolower($key);
if (!$overwrite && isset($this->header[$key])) { if (!$overwrite && isset($this->header[$key])) {
return false; return false;
@ -98,7 +98,7 @@ final class Header extends HeaderAbstract
*/ */
public static function isSecurityHeader(string $key) : bool public static function isSecurityHeader(string $key) : bool
{ {
$key = strtolower($key); $key = \strtolower($key);
return $key === 'content-security-policy' return $key === 'content-security-policy'
|| $key === 'x-xss-protection' || $key === 'x-xss-protection'
@ -139,16 +139,17 @@ final class Header extends HeaderAbstract
*/ */
public static function getAllHeaders() : array public static function getAllHeaders() : array
{ {
if (function_exists('getallheaders')) { if (\function_exists('getallheaders')) {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
return getallheaders(); return \getallheaders();
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
$headers = []; $headers = [];
foreach ($_SERVER as $name => $value) { foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') { $part = \substr($name, 5);
$headers[\str_replace(' ', '-', ucwords(strtolower(\str_replace('_', ' ', substr($name, 5)))))] = $value; if ($part === 'HTTP_') {
$headers[\str_replace(' ', '-', \ucwords(\strtolower(\str_replace('_', ' ', $part))))] = $value;
} }
} }
@ -200,7 +201,7 @@ final class Header extends HeaderAbstract
*/ */
public function get(string $key) : array public function get(string $key) : array
{ {
return $this->header[strtolower($key)] ?? []; return $this->header[\strtolower($key)] ?? [];
} }
/** /**

View File

@ -105,7 +105,7 @@ final class Request extends RequestAbstract
$this->setupUriBuilder(); $this->setupUriBuilder();
} }
$this->data = array_change_key_case($this->data, CASE_LOWER); $this->data = \array_change_key_case($this->data, CASE_LOWER);
} }
/** /**
@ -140,13 +140,16 @@ final class Request extends RequestAbstract
{ {
if (isset($_SERVER['CONTENT_TYPE'])) { if (isset($_SERVER['CONTENT_TYPE'])) {
if (\stripos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) { if (\stripos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
if (($json = \json_decode(($input = \file_get_contents('php://input')), true)) === false || $json === null) { $input = \file_get_contents('php://input');
$json = \json_decode($input === false ? '' : $input, true);
if ($input === false || $json === false || $json === null) {
throw new \Exception('Is not valid json ' . $input); throw new \Exception('Is not valid json ' . $input);
} }
$this->data += $json; $this->data += $json;
} elseif (\stripos($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') !== false) { } elseif (\stripos($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') !== false) {
parse_str(file_get_contents('php://input'), $temp); $content = \file_get_contents('php://input');
\parse_str($content === false ? '' : $content, $temp);
$this->data += $temp; $this->data += $temp;
} }
} }
@ -246,7 +249,7 @@ final class Request extends RequestAbstract
$paths[] = $pathArray[$i]; $paths[] = $pathArray[$i];
} }
$this->hash[] = sha1(implode('', $paths)); $this->hash[] = sha1(\implode('', $paths));
} }
} }
@ -292,10 +295,10 @@ final class Request extends RequestAbstract
{ {
if ($this->browser === null) { if ($this->browser === null) {
$arr = BrowserType::getConstants(); $arr = BrowserType::getConstants();
$httpUserAgent = strtolower($_SERVER['HTTP_USER_AGENT']); $httpUserAgent = \strtolower($_SERVER['HTTP_USER_AGENT']);
foreach ($arr as $key => $val) { foreach ($arr as $key => $val) {
if (stripos($httpUserAgent, $val)) { if (\stripos($httpUserAgent, $val)) {
$this->browser = $val; $this->browser = $val;
return $this->browser; return $this->browser;
@ -333,10 +336,10 @@ final class Request extends RequestAbstract
{ {
if ($this->os === null) { if ($this->os === null) {
$arr = OSType::getConstants(); $arr = OSType::getConstants();
$httpUserAgent = strtolower($_SERVER['HTTP_USER_AGENT']); $httpUserAgent = \strtolower($_SERVER['HTTP_USER_AGENT']);
foreach ($arr as $key => $val) { foreach ($arr as $key => $val) {
if (stripos($httpUserAgent, $val)) { if (\stripos($httpUserAgent, $val)) {
$this->os = $val; $this->os = $val;
return $this->os; return $this->os;
@ -397,7 +400,8 @@ final class Request extends RequestAbstract
*/ */
public function getBody() : string public function getBody() : string
{ {
return \file_get_contents('php://input'); $body = \file_get_contents('php://input');
return $body === false ? '' : $body;
} }
/** /**
@ -462,7 +466,7 @@ final class Request extends RequestAbstract
{ {
if ($this->getMethod() === RequestMethod::GET && !empty($this->data)) { if ($this->getMethod() === RequestMethod::GET && !empty($this->data)) {
return $this->uri->__toString() return $this->uri->__toString()
. (parse_url($this->uri->__toString(), PHP_URL_QUERY) ? '&' : '?') . (\parse_url($this->uri->__toString(), PHP_URL_QUERY) ? '&' : '?')
. http_build_query($this->data); . http_build_query($this->data);
} }

View File

@ -106,7 +106,7 @@ final class Response extends ResponseAbstract implements RenderableInterface
foreach ($types as $type) { foreach ($types as $type) {
if (\stripos($type, MimeType::M_JSON) !== false) { if (\stripos($type, MimeType::M_JSON) !== false) {
return \json_encode($this->jsonSerialize()); return (string) \json_encode($this->jsonSerialize());
} }
} }
@ -131,6 +131,8 @@ final class Response extends ResponseAbstract implements RenderableInterface
$render .= $response->serialize(); $render .= $response->serialize();
} elseif (\is_string($response) || \is_numeric($response)) { } elseif (\is_string($response) || \is_numeric($response)) {
$render .= $response; $render .= $response;
} elseif (\is_array($response)) {
$render .= \json_encode($response);
} else { } else {
throw new \Exception('Wrong response type'); throw new \Exception('Wrong response type');
} }
@ -152,7 +154,7 @@ final class Response extends ResponseAbstract implements RenderableInterface
{ {
$types = $this->header->get('Content-Type'); $types = $this->header->get('Content-Type');
if (\stripos($types[0], MimeType::M_HTML) !== false) { if (\stripos($types[0], MimeType::M_HTML) !== false) {
return \trim(\preg_replace('/(\s{2,}|\n|\t)(?![^<>]*<\/pre>)/', ' ', $render)); return \trim(\preg_replace('/(?s)<pre[^<]*>.*?<\/pre>(*SKIP)(*F)|(\s{2,}|\n|\t)/', ' ', $render));
} }
return $render; return $render;

View File

@ -36,35 +36,47 @@ final class Rest
*/ */
public static function request(Request $request) : string public static function request(Request $request) : string
{ {
$curl = curl_init(); $curl = \curl_init();
if ($curl === false) {
throw new \Exception();
}
curl_setopt($curl, CURLOPT_NOBODY, true);
curl_setopt($curl, CURLOPT_HEADER, false);
switch ($request->getMethod()) { switch ($request->getMethod()) {
case RequestMethod::GET:
curl_setopt($curl, CURLOPT_HTTPGET, true);
break;
case RequestMethod::PUT: case RequestMethod::PUT:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); \curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
break; break;
case RequestMethod::DELETE: case RequestMethod::DELETE:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); \curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
break; break;
} }
if ($request->getMethod() !== RequestMethod::GET) { if ($request->getMethod() !== RequestMethod::GET) {
curl_setopt($curl, CURLOPT_POST, 1); \curl_setopt($curl, CURLOPT_POST, 1);
if ($request->getData() !== null) { if ($request->getData() !== null) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $request->getData()); \curl_setopt($curl, CURLOPT_POSTFIELDS, $request->getData());
} }
} }
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); if ($request->getUri()->getUser() !== '') {
curl_setopt($curl, CURLOPT_USERPWD, 'username:password'); \curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
\curl_setopt($curl, CURLOPT_USERPWD, $request->getUri()->getUserInfo());
}
curl_setopt($curl, CURLOPT_URL, $request->__toString()); \curl_setopt($curl, CURLOPT_URL, $request->__toString());
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); \curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl); $result = \curl_exec($curl);
curl_close($curl); \curl_close($curl);
return $result; return \is_bool($result) ? '' : $result;
} }
} }

View File

@ -123,7 +123,7 @@ class Mail
/** /**
* Word wrap. * Word wrap.
* *
* @var string * @var int
* @since 1.0.0 * @since 1.0.0
*/ */
protected $wordWrap = 78; protected $wordWrap = 78;

View File

@ -85,7 +85,9 @@ final class InfoManager
throw new PathException($this->path); throw new PathException($this->path);
} }
$this->info = \json_decode(file_get_contents($this->path), true); $contents = \file_get_contents($this->path);
$info = \json_decode($contents === false ? '[]' : $contents, true);
$this->info = $info === false ? [] : $info;
} }
/** /**

View File

@ -18,6 +18,7 @@ use phpOMS\DataStorage\Database\DatabaseType;
use phpOMS\DataStorage\Database\Exception\InvalidDatabaseTypeException; use phpOMS\DataStorage\Database\Exception\InvalidDatabaseTypeException;
use phpOMS\DataStorage\Database\DatabasePool; use phpOMS\DataStorage\Database\DatabasePool;
use phpOMS\System\File\Local\Directory; use phpOMS\System\File\Local\Directory;
use phpOMS\System\File\Local\File;
use phpOMS\System\File\PathException; use phpOMS\System\File\PathException;
use phpOMS\System\File\PermissionException; use phpOMS\System\File\PermissionException;
use phpOMS\Utils\Parser\Php\ArrayParser; use phpOMS\Utils\Parser\Php\ArrayParser;
@ -73,7 +74,6 @@ class InstallerAbstract
$sth->bindValue(':from', $val['from'], \PDO::PARAM_STR); $sth->bindValue(':from', $val['from'], \PDO::PARAM_STR);
$sth->bindValue(':for', $val['for'], \PDO::PARAM_STR); $sth->bindValue(':for', $val['for'], \PDO::PARAM_STR);
$sth->bindValue(':file', $val['file'], \PDO::PARAM_STR); $sth->bindValue(':file', $val['file'], \PDO::PARAM_STR);
$sth->execute(); $sth->execute();
} }
} }
@ -115,7 +115,7 @@ class InstallerAbstract
*/ */
private static function activate(DatabasePool $dbPool, InfoManager $info) : void private static function activate(DatabasePool $dbPool, InfoManager $info) : void
{ {
/** @var ActivateAbstract $class */ /** @var StatusAbstract $class */
$class = '\Modules\\' . $info->getDirectory() . '\Admin\Status'; $class = '\Modules\\' . $info->getDirectory() . '\Admin\Status';
$class::activate($dbPool, $info); $class::activate($dbPool, $info);
} }
@ -150,11 +150,13 @@ class InstallerAbstract
{ {
$directories = new Directory(\dirname($info->getPath()) . '/Admin/Routes'); $directories = new Directory(\dirname($info->getPath()) . '/Admin/Routes');
foreach ($directories as $key => $subdir) { foreach ($directories as $key => $child) {
if ($subdir instanceof Directory) { if ($child instanceof Directory) {
foreach ($subdir as $key2 => $file) { foreach ($child as $key2 => $file) {
self::installRoutes(__DIR__ . '/../../' . $subdir->getName() . '/' . basename($file->getName(), '.php') . '/Routes.php', $file->getPath()); self::installRoutes(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Routes.php', $file->getPath());
} }
} elseif ($child instanceof File) {
self::installRoutes(__DIR__ . '/../../' . $child->getName() . '/Routes.php', $child->getPath());
} }
} }
} }
@ -185,7 +187,7 @@ class InstallerAbstract
throw new PathException($destRoutePath); throw new PathException($destRoutePath);
} }
if (!is_writable($destRoutePath)) { if (!\is_writable($destRoutePath)) {
throw new PermissionException($destRoutePath); throw new PermissionException($destRoutePath);
} }
@ -194,7 +196,7 @@ class InstallerAbstract
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$moduleRoutes = include $srcRoutePath; $moduleRoutes = include $srcRoutePath;
$appRoutes = array_merge_recursive($appRoutes, $moduleRoutes); $appRoutes = \array_merge_recursive($appRoutes, $moduleRoutes);
\file_put_contents($destRoutePath, '<?php return ' . ArrayParser::serializeArray($appRoutes) . ';', LOCK_EX); \file_put_contents($destRoutePath, '<?php return ' . ArrayParser::serializeArray($appRoutes) . ';', LOCK_EX);
} }
@ -214,11 +216,13 @@ class InstallerAbstract
{ {
$directories = new Directory(\dirname($info->getPath()) . '/Admin/Hooks'); $directories = new Directory(\dirname($info->getPath()) . '/Admin/Hooks');
foreach ($directories as $key => $subdir) { foreach ($directories as $key => $child) {
if ($subdir instanceof Directory) { if ($child instanceof Directory) {
foreach ($subdir as $key2 => $file) { foreach ($child as $key2 => $file) {
self::installHooks(__DIR__ . '/../../' . $subdir->getName() . '/' . basename($file->getName(), '.php') . '/Hooks.php', $file->getPath()); self::installHooks(__DIR__ . '/../../' . $child->getName() . '/' . \basename($file->getName(), '.php') . '/Hooks.php', $file->getPath());
} }
} elseif ($child instanceof File) {
self::installRoutes(__DIR__ . '/../../' . $child->getName() . '/Hooks.php', $child->getPath());
} }
} }
} }
@ -249,7 +253,7 @@ class InstallerAbstract
throw new PathException($destHookPath); throw new PathException($destHookPath);
} }
if (!is_writable($destHookPath)) { if (!\is_writable($destHookPath)) {
throw new PermissionException($destHookPath); throw new PermissionException($destHookPath);
} }
@ -258,7 +262,7 @@ class InstallerAbstract
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$moduleHooks = include $srcHookPath; $moduleHooks = include $srcHookPath;
$appHooks = array_merge_recursive($appHooks, $moduleHooks); $appHooks = \array_merge_recursive($appHooks, $moduleHooks);
\file_put_contents($destHookPath, '<?php return ' . ArrayParser::serializeArray($appHooks) . ';', LOCK_EX); \file_put_contents($destHookPath, '<?php return ' . ArrayParser::serializeArray($appHooks) . ';', LOCK_EX);
} }

View File

@ -120,7 +120,7 @@ abstract class ModuleAbstract
$lang = []; $lang = [];
if (file_exists($oldPath = __DIR__ . '/../../Modules/' . static::MODULE_NAME . '/Theme/' . $destination . '/Lang/' . $language . '.lang.php')) { if (file_exists($oldPath = __DIR__ . '/../../Modules/' . static::MODULE_NAME . '/Theme/' . $destination . '/Lang/' . $language . '.lang.php')) {
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$lang = include $oldPath; return include $oldPath;
} }
return $lang; return $lang;

View File

@ -79,7 +79,7 @@ final class ModuleFactory
self::$loaded[$module] = $obj; self::$loaded[$module] = $obj;
self::registerRequesting($obj); self::registerRequesting($obj);
self::registerProvided($obj); self::registerProvided($obj);
} catch (\Exception $e) { } catch (\Throwable $e) {
self::$loaded[$module] = new NullModule($app); self::$loaded[$module] = new NullModule($app);
} }
} else { } else {

View File

@ -58,7 +58,7 @@ final class ModuleManager
* @var array * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
private $installed = null; private $installed = [];
/** /**
* All active modules (on all pages not just the ones that are running now). * All active modules (on all pages not just the ones that are running now).
@ -66,7 +66,7 @@ final class ModuleManager
* @var array * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
private $active = null; private $active = [];
/** /**
* Module path. * Module path.
@ -82,7 +82,7 @@ final class ModuleManager
* @var array * @var array
* @since 1.0.0 * @since 1.0.0
*/ */
private $all = null; private $all = [];
/** /**
* To load based on request uri. * To load based on request uri.
@ -195,18 +195,33 @@ final class ModuleManager
*/ */
public function getActiveModules(bool $useCache = true) : array public function getActiveModules(bool $useCache = true) : array
{ {
if ($this->active === null || !$useCache) { if (empty($this->active) || !$useCache) {
switch ($this->app->dbPool->get('select')->getType()) { switch ($this->app->dbPool->get('select')->getType()) {
case DatabaseType::MYSQL: case DatabaseType::MYSQL:
$sth = $this->app->dbPool->get('select')->con->prepare('SELECT `module_path` FROM `' . $this->app->dbPool->get('select')->prefix . 'module` WHERE `module_active` = 1'); $sth = $this->app->dbPool->get('select')->con->prepare('SELECT `module_path` FROM `' . $this->app->dbPool->get('select')->prefix . 'module` WHERE `module_active` = 1');
$sth->execute(); $sth->execute();
$this->active = $sth->fetchAll(\PDO::FETCH_COLUMN); $active = $sth->fetchAll(\PDO::FETCH_COLUMN);
foreach ($active as $module) {
$path = $this->modulePath . '/' . $module . '/info.json';
if (!\file_exists($path)) {
continue;
// throw new PathException($path);
}
$content = \file_get_contents($path);
$json = \json_decode($content === false ? '[]' : $content, true);
$this->active[$json['name']['internal']] = $json === false ? [] : $json;
}
break; break;
default: default:
throw new InvalidDatabaseTypeException($this->app->dbPool->get('select')->getType()); throw new InvalidDatabaseTypeException($this->app->dbPool->get('select')->getType());
} }
} }
return $this->active; return $this->active;
} }
@ -221,7 +236,7 @@ final class ModuleManager
*/ */
public function isActive(string $module) : bool public function isActive(string $module) : bool
{ {
return \in_array($module, $this->getActiveModules(false)); return isset($this->getActiveModules(false)[$module]);
} }
/** /**
@ -233,7 +248,7 @@ final class ModuleManager
*/ */
public function getAllModules() : array public function getAllModules() : array
{ {
if ($this->all === null) { if (empty($this->all)) {
chdir($this->modulePath); chdir($this->modulePath);
$files = glob('*', GLOB_ONLYDIR); $files = glob('*', GLOB_ONLYDIR);
$c = count($files); $c = count($files);
@ -246,8 +261,9 @@ final class ModuleManager
// throw new PathException($path); // throw new PathException($path);
} }
$json = \json_decode(file_get_contents($path), true); $content = \file_get_contents($path);
$this->all[$json['name']['internal']] = $json; $json = \json_decode($content === false ? '[]' : $content, true);
$this->all[$json['name']['internal']] = $json === false ? [] : $json;
} }
} }
@ -277,12 +293,26 @@ final class ModuleManager
*/ */
public function getInstalledModules(bool $useCache = true) : array public function getInstalledModules(bool $useCache = true) : array
{ {
if ($this->installed === null || !$useCache) { if (empty($this->installed) || !$useCache) {
switch ($this->app->dbPool->get('select')->getType()) { switch ($this->app->dbPool->get('select')->getType()) {
case DatabaseType::MYSQL: case DatabaseType::MYSQL:
$sth = $this->app->dbPool->get('select')->con->prepare('SELECT `module_id`,`module_theme`,`module_version` FROM `' . $this->app->dbPool->get('select')->prefix . 'module`'); $sth = $this->app->dbPool->get('select')->con->prepare('SELECT `module_path` FROM `' . $this->app->dbPool->get('select')->prefix . 'module`');
$sth->execute(); $sth->execute();
$this->installed = $sth->fetchAll(\PDO::FETCH_GROUP); $installed = $sth->fetchAll(\PDO::FETCH_COLUMN);
foreach ($installed as $module) {
$path = $this->modulePath . '/' . $module . '/info.json';
if (!\file_exists($path)) {
continue;
// throw new PathException($path);
}
$content = \file_get_contents($path);
$json = \json_decode($content === false ? '[]' : $content, true);
$this->installed[$json['name']['internal']] = $json === false ? [] : $json;
}
break; break;
default: default:
throw new InvalidDatabaseTypeException($this->app->dbPool->get('select')->getType()); throw new InvalidDatabaseTypeException($this->app->dbPool->get('select')->getType());
@ -303,7 +333,7 @@ final class ModuleManager
*/ */
private function loadInfo(string $module) : InfoManager private function loadInfo(string $module) : InfoManager
{ {
$path = realpath($oldPath = $this->modulePath . '/' . $module . '/info.json'); $path = \realpath($oldPath = $this->modulePath . '/' . $module . '/info.json');
if ($path === false) { if ($path === false) {
throw new PathException($oldPath); throw new PathException($oldPath);

View File

@ -109,7 +109,9 @@ final class PackageManager
throw new PathException($this->extractPath); throw new PathException($this->extractPath);
} }
$this->info = \json_decode(file_get_contents($this->extractPath . '/info.json'), true); $contents = \file_get_contents($this->extractPath . '/info.json');
$info = \json_decode($contents === false ? '[]' : $contents, true);
$this->info = $info === false ? [] : $info;
} }
/** /**
@ -121,7 +123,8 @@ final class PackageManager
*/ */
public function isValid() : bool public function isValid() : bool
{ {
return $this->authenticate(file_get_contents($this->extractPath . '/package.cert'), $this->hashFiles()); $contents = \file_get_contents($this->extractPath . '/package.cert');
return $this->authenticate($contents === false ? '' : $contents, $this->hashFiles());
} }
/** /**
@ -141,10 +144,15 @@ final class PackageManager
continue; continue;
} }
\sodium_crypto_generichash_update($state, \file_get_contents($this->extractPath . '/package/' . $file)); $contents = \file_get_contents($this->extractPath . '/package/' . $file);
if ($contents === false) {
throw new \Exception();
}
\sodium_crypto_generichash_update($state, $contents);
} }
return \sodium_crypto_generichash_final(); return \sodium_crypto_generichash_final($state);
} }
/** /**

View File

@ -1,4 +1,4 @@
[![Maintainability](https://api.codeclimate.com/v1/badges/7e83e9f82ea1b19e1574/maintainability)](https://codeclimate.com/github/Orange-Management/phpOMS/maintainability) [![Build Status](https://travis-ci.org/Orange-Management/phpOMS.svg?branch=develop)](https://travis-ci.org/Orange-Management/phpOMS)
# General # General

View File

@ -35,15 +35,6 @@ final class Router
*/ */
private $routes = []; private $routes = [];
/**
* Constructor.
*
* @since 1.0.0
*/
public function __construct()
{
}
/** /**
* Add routes from file. * Add routes from file.
* *
@ -55,7 +46,7 @@ final class Router
*/ */
public function importFromFile(string $path) : bool public function importFromFile(string $path) : bool
{ {
if (file_exists($path)) { if (\file_exists($path)) {
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
$this->routes += include $path; $this->routes += include $path;
@ -69,7 +60,7 @@ final class Router
* Add route. * Add route.
* *
* @param string $route Route regex * @param string $route Route regex
* @param mixed $destination Destination e.g. Module:function & verb * @param mixed $destination Destination e.g. Module:function string or callback
* @param int $verb Request verb * @param int $verb Request verb
* *
* @return void * @return void
@ -100,22 +91,22 @@ final class Router
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function route($request, int $verb = RouteVerb::GET) : array public function route(string $request, int $verb = RouteVerb::GET, string $app = '', int $orgId = 1, $account = null) : array
{ {
if ($request instanceof RequestAbstract) {
$uri = $request->getUri()->getRoute();
$verb = $request->getRouteVerb();
} elseif (is_string($request)) {
$uri = $request;
} else {
throw new \InvalidArgumentException();
}
$bound = []; $bound = [];
foreach ($this->routes as $route => $destination) { foreach ($this->routes as $route => $destination) {
foreach ($destination as $d) { foreach ($destination as $d) {
if ($this->match($route, $d['verb'], $uri, $verb)) { if ($this->match($route, $d['verb'], $request, $verb)) {
$bound[] = ['dest' => $d['dest']]; if (!isset($d['permission'])
|| !isset($account)
|| (isset($d['permission'])
&& isset($account)
&& $account->hasPermission($d['permission']['type'], $orgId, $app, $d['permission']['module'], $d['permission']['state']))
) {
$bound[] = ['dest' => $d['dest']];
} else {
\array_merge($bound, $this->route('/' . $app . '/e403', $verb));
}
} }
} }
} }

View File

@ -104,7 +104,12 @@ final class PhpCode
*/ */
public static function isDisabled(array $functions) : bool public static function isDisabled(array $functions) : bool
{ {
$disabled = ini_get('disable_functions'); $disabled = \ini_get('disable_functions');
if ($disabled === false) {
return true;
}
$disabled = \str_replace(' ', '', $disabled); $disabled = \str_replace(' ', '', $disabled);
$disabled = \explode(',', $disabled); $disabled = \explode(',', $disabled);
@ -149,6 +154,21 @@ final class PhpCode
*/ */
public static function validateFileIntegrity(string $source, string $hash) : bool public static function validateFileIntegrity(string $source, string $hash) : bool
{ {
return md5_file($source) === $hash; return \md5_file($source) === $hash;
}
/**
* Validate code integrety
*
* @param string $source Source code
* @param string $remote Remote code
*
* @return bool
*
* @since 1.0.0
*/
public static function validateStringIntegrity(string $source, string $remote) : bool
{
return $source === $remote;
} }
} }

View File

@ -26,6 +26,13 @@ namespace phpOMS\Stdlib\Base;
*/ */
abstract class EnumArray abstract class EnumArray
{ {
/**
* Constants.
*
* @var array
* @since 1.0.0
*/
protected static $constants = [];
/** /**
* Checking enum name. * Checking enum name.

View File

@ -115,15 +115,16 @@ class Iban implements \Serializable
{ {
$country = $this->getCountry(); $country = $this->getCountry();
$layout = \str_replace(' ', '', IbanEnum::getByName('C_' . $country)); $layout = \str_replace(' ', '', IbanEnum::getByName('C_' . $country));
$start = \stripos($layout, $sequence);
$end = \strrpos($layout, $sequence);
$start = \stripos($layout, $sequence); if ($start === false || $end === false) {
$end = strrpos($layout, $sequence);
if ($start === false) {
return ''; return '';
} }
return substr($this->iban, $start, $end - $start + 1); $sequence = \substr($this->iban, $start, $end - $start + 1);
return $sequence === false ? '' : $sequence;
} }
/** /**
@ -135,7 +136,9 @@ class Iban implements \Serializable
*/ */
public function getCountry() : string public function getCountry() : string
{ {
return substr($this->iban, 0, 2); $country = \substr($this->iban, 0, 2);
return $country === false ? '?' : $country;
} }
/** /**

View File

@ -297,7 +297,7 @@ class Location implements \JsonSerializable, \Serializable
*/ */
public function serialize() : string public function serialize() : string
{ {
return \json_encode($this->jsonSerialize()); return (string) \json_encode($this->jsonSerialize());
} }
/** /**

View File

@ -97,8 +97,8 @@ class SmartDateTime extends \DateTime
$yearNew = (int) $this->format('Y') + $y + $yearChange; $yearNew = (int) $this->format('Y') + $y + $yearChange;
$monthNew = ((int) $this->format('m') + $m) % 12; $monthNew = ((int) $this->format('m') + $m) % 12;
$monthNew = $monthNew === 0 ? 12 : $monthNew < 0 ? 12 + $monthNew : $monthNew; $monthNew = $monthNew === 0 ? 12 : $monthNew < 0 ? 12 + $monthNew : $monthNew;
$dayMonthOld = cal_days_in_month($calendar, (int) $this->format('m'), (int) $this->format('Y')); $dayMonthOld = \cal_days_in_month($calendar, (int) $this->format('m'), (int) $this->format('Y'));
$dayMonthNew = cal_days_in_month($calendar, $monthNew, $yearNew); $dayMonthNew = \cal_days_in_month($calendar, $monthNew, $yearNew);
$dayOld = (int) $this->format('d'); $dayOld = (int) $this->format('d');
if ($dayOld > $dayMonthNew) { if ($dayOld > $dayMonthNew) {
@ -219,7 +219,13 @@ class SmartDateTime extends \DateTime
*/ */
public static function getDayOfWeek(int $y, int $m, int $d) : int public static function getDayOfWeek(int $y, int $m, int $d) : int
{ {
return (int) date('w', strtotime($d . '-' . $m . '-' . $y)); $time = \strtotime($d . '-' . $m . '-' . $y);
if ($time === false) {
return -1;
}
return (int) date('w', $time);
} }
/** /**

View File

@ -53,14 +53,15 @@ class PriorityQueue implements \Countable, \Serializable
/** /**
* Insert element into queue. * Insert element into queue.
* *
* @param mixed $data Queue element * @param mixed $data Queue element
* @param float $priority Priority of this element * @param string $job Job cmd
* @param float $priority Priority of this element
* *
* @return int * @return int
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public function insert($data, float $priority = 1.0) : int public function insert($data, string $job, float $priority = 1.0) : int
{ {
do { do {
$key = rand(); $key = rand();
@ -78,6 +79,7 @@ class PriorityQueue implements \Countable, \Serializable
$pos++; $pos++;
} }
$original = [];
array_splice($original, $pos, 0, [$key => ['key' => $key, 'job' => $job, 'priority' => $priority]]); array_splice($original, $pos, 0, [$key => ['key' => $key, 'job' => $job, 'priority' => $priority]]);
} }
@ -184,7 +186,7 @@ class PriorityQueue implements \Countable, \Serializable
*/ */
public function serialize() : string public function serialize() : string
{ {
return \json_encode($this->queue); return (string) \json_encode($this->queue);
} }
/** /**

View File

@ -205,7 +205,7 @@ interface ContainerInterface
* @param bool $recursive Consider subdirectories * @param bool $recursive Consider subdirectories
* @param array $ignore Files/paths to ignore (no regex) * @param array $ignore Files/paths to ignore (no regex)
* *
* @return string * @return int
* *
* @since 1.0.0 * @since 1.0.0
*/ */

View File

@ -92,7 +92,7 @@ final class FileUtils
*/ */
public static function absolute(string $origPath) : string public static function absolute(string $origPath) : string
{ {
if (!\file_exists($origPath)) { if (!\file_exists($origPath) || \realpath($origPath) === false) {
$startsWithSlash = strpos($origPath, '/') === 0 ? '/' : ''; $startsWithSlash = strpos($origPath, '/') === 0 ? '/' : '';
$path = []; $path = [];
@ -106,15 +106,34 @@ final class FileUtils
if ($part !== '..') { if ($part !== '..') {
$path[] = $part; $path[] = $part;
} elseif (!empty($path)) { } elseif (!empty($path)) {
array_pop($path); \array_pop($path);
} else { } else {
throw new PathException($origPath); throw new PathException($origPath);
} }
} }
return $startsWithSlash . implode('/', $path); return $startsWithSlash . \implode('/', $path);
} }
return realpath($origPath); return \realpath($origPath);
}
/**
* Change encoding of file
*
* @param string $file Path to file which should be re-encoded
* @param string $encoding New file encoding
*
* @return void
*
* @since 1.0.0
*/
public static function changeFileEncoding(string $file, string $encoding) : void
{
$content = \file_get_contents($file);
if ($content !== false && preg_match('!!u', $content)) {
\file_put_contents($file, \mb_convert_encoding($content, 'UTF-8', mb_list_encodings()));
}
} }
} }

View File

@ -178,6 +178,22 @@ class Directory extends FileAbstract implements DirectoryInterface
} }
/**
* {@inheritdoc}
*/
public static function dirname(string $path) : string
{
}
/**
* {@inheritdoc}
*/
public static function dirpath(string $path) : string
{
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -138,6 +138,14 @@ class File extends FileAbstract implements FileInterface
return $content; return $content;
} }
/**
* {@inheritdoc}
*/
public static function count(string $path, bool $recursive = true, array $ignore = []) : int
{
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -71,7 +71,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
* @param string $path Path * @param string $path Path
* @param string $filter Filter * @param string $filter Filter
* *
* @return string[] * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@ -105,7 +105,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
* @param string $extension Extension * @param string $extension Extension
* @param string $exclude Pattern to exclude * @param string $exclude Pattern to exclude
* *
* @return string[] * @return array
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@ -168,6 +168,10 @@ final class Directory extends FileAbstract implements DirectoryInterface
$countSize = 0; $countSize = 0;
$directories = \scandir($dir); $directories = \scandir($dir);
if ($directories === false) {
return $countSize;
}
foreach ($directories as $key => $filename) { foreach ($directories as $key => $filename) {
if ($filename === ".." || $filename === ".") { if ($filename === ".." || $filename === ".") {
continue; continue;
@ -181,7 +185,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
} }
} }
return (int) $countSize; return $countSize;
} }
/** /**
@ -198,6 +202,10 @@ final class Directory extends FileAbstract implements DirectoryInterface
$ignore[] = '.'; $ignore[] = '.';
$ignore[] = '..'; $ignore[] = '..';
if ($files === false) {
return $size;
}
foreach ($files as $t) { foreach ($files as $t) {
if (\in_array($t, $ignore)) { if (\in_array($t, $ignore)) {
continue; continue;
@ -221,6 +229,10 @@ final class Directory extends FileAbstract implements DirectoryInterface
{ {
$files = \scandir($path); $files = \scandir($path);
if ($files === false) {
return false;
}
/* Removing . and .. */ /* Removing . and .. */
unset($files[1]); unset($files[1]);
unset($files[0]); unset($files[0]);
@ -260,7 +272,9 @@ final class Directory extends FileAbstract implements DirectoryInterface
} }
$created = new \DateTime('now'); $created = new \DateTime('now');
$created->setTimestamp(\filemtime($path)); $time = \filemtime($path);
$created->setTimestamp($time === false ? 0 : $time);
return $created; return $created;
} }
@ -275,7 +289,9 @@ final class Directory extends FileAbstract implements DirectoryInterface
} }
$changed = new \DateTime(); $changed = new \DateTime();
$changed->setTimestamp(\filectime($path)); $time = \filectime($path);
$changed->setTimestamp($time === false ? 0 : $time);
return $changed; return $changed;
} }
@ -289,7 +305,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
throw new PathException($path); throw new PathException($path);
} }
return \fileowner($path); return (int) \fileowner($path);
} }
/** /**
@ -301,7 +317,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
throw new PathException($path); throw new PathException($path);
} }
return \fileperms($path); return (int) \fileperms($path);
} }
/** /**

View File

@ -56,7 +56,7 @@ final class File extends FileAbstract implements FileInterface
{ {
parent::index(); parent::index();
$this->size = \filesize($this->path); $this->size = (int) \filesize($this->path);
} }
/** /**
@ -98,7 +98,9 @@ final class File extends FileAbstract implements FileInterface
throw new PathException($path); throw new PathException($path);
} }
return \file_get_contents($path); $contents = \file_get_contents($path);
return $contents === false ? '' : $contents;
} }
/** /**
@ -166,7 +168,9 @@ final class File extends FileAbstract implements FileInterface
throw new PathException($path); throw new PathException($path);
} }
return self::createFileTime(\filemtime($path)); $time = \filemtime($path);
return self::createFileTime($time === false ? 0 : $time);
} }
/** /**
@ -178,7 +182,9 @@ final class File extends FileAbstract implements FileInterface
throw new PathException($path); throw new PathException($path);
} }
return self::createFileTime(\filemtime($path)); $time = \filemtime($path);
return self::createFileTime($time === false ? 0 : $time);
} }
/** /**
@ -207,7 +213,7 @@ final class File extends FileAbstract implements FileInterface
throw new PathException($path); throw new PathException($path);
} }
return filesize($path); return (int) \filesize($path);
} }
/** /**
@ -219,7 +225,7 @@ final class File extends FileAbstract implements FileInterface
throw new PathException($path); throw new PathException($path);
} }
return \fileowner($path); return (int) \fileowner($path);
} }
/** /**
@ -231,7 +237,7 @@ final class File extends FileAbstract implements FileInterface
throw new PathException($path); throw new PathException($path);
} }
return \fileperms($path); return (int) \fileperms($path);
} }
/** /**
@ -245,7 +251,7 @@ final class File extends FileAbstract implements FileInterface
*/ */
public static function dirname(string $path) : string public static function dirname(string $path) : string
{ {
return basename(\dirname($path)); return \basename(\dirname($path));
} }
/** /**
@ -259,7 +265,7 @@ final class File extends FileAbstract implements FileInterface
*/ */
public static function dirpath(string $path) : string public static function dirpath(string $path) : string
{ {
return dirname($path); return \dirname($path);
} }
/** /**
@ -267,7 +273,7 @@ final class File extends FileAbstract implements FileInterface
*/ */
public static function copy(string $from, string $to, bool $overwrite = false) : bool public static function copy(string $from, string $to, bool $overwrite = false) : bool
{ {
if (!is_file($from)) { if (!\is_file($from)) {
throw new PathException($from); throw new PathException($from);
} }
@ -325,7 +331,7 @@ final class File extends FileAbstract implements FileInterface
*/ */
public function getDirName() : string public function getDirName() : string
{ {
return basename(\dirname($this->path)); return \basename(\dirname($this->path));
} }
/** /**
@ -375,7 +381,9 @@ final class File extends FileAbstract implements FileInterface
*/ */
public function getContent() : string public function getContent() : string
{ {
return \file_get_contents($this->path); $contents = \file_get_contents($this->path);
return $contents === false ? '' : $contents;
} }
/** /**

View File

@ -185,9 +185,15 @@ abstract class FileAbstract implements ContainerInterface
*/ */
public function index() : void public function index() : void
{ {
$this->createdAt->setTimestamp(filemtime($this->path)); $mtime = \filemtime($this->path);
$this->changedAt->setTimestamp(filectime($this->path)); $ctime = \filectime($this->path);
$this->owner = fileowner($this->path);
$this->permission = (int) substr(sprintf('%o', fileperms($this->path)), -4); $this->createdAt->setTimestamp($mtime === false ? 0 : $mtime);
$this->changedAt->setTimestamp($ctime === false ? 0 : $ctime);
$owner = \fileowner($this->path);
$this->owner = $owner === false ? 0 : $owner;
$this->permission = (int) \substr(\sprintf('%o', \fileperms($this->path)), -4);
} }
} }

View File

@ -54,13 +54,7 @@ class LocalStorage extends StorageAbstract
} }
/** /**
* Get the internal class type (directory or file) based on path. * {@inheritdoc}
*
* @param string $path Path to the directory or file
*
* @return string Class namespace
*
* @since 1.0.0
*/ */
protected static function getClassType(string $path) : string protected static function getClassType(string $path) : string
{ {

View File

@ -43,6 +43,17 @@ abstract class StorageAbstract
*/ */
abstract public static function getInstance() : StorageAbstract; abstract public static function getInstance() : StorageAbstract;
/**
* Get the internal class type (directory or file) based on path.
*
* @param string $path Path to the directory or file
*
* @return string Class namespace
*
* @since 1.0.0
*/
abstract protected static function getClassType(string $path) : string;
/** /**
* Get storage type. * Get storage type.
* *
@ -265,7 +276,7 @@ abstract class StorageAbstract
* @param bool $recursive Consider subdirectories * @param bool $recursive Consider subdirectories
* @param array $ignore Files/paths to ignore (no regex) * @param array $ignore Files/paths to ignore (no regex)
* *
* @return string * @return int
* *
* @since 1.0.0 * @since 1.0.0
*/ */

View File

@ -46,25 +46,27 @@ final class SystemUtils
{ {
$mem = 0; $mem = 0;
if (stristr(PHP_OS, 'WIN')) { if (\stristr(PHP_OS, 'WIN')) {
$mem = null; $memArr = [];
exec('wmic memorychip get capacity', $mem); exec('wmic memorychip get capacity', $memArr);
/** @var array $mem */ $mem = \array_sum($memArr) / 1024;
$mem = array_sum($mem) / 1024; } elseif (\stristr(PHP_OS, 'LINUX')) {
} elseif (stristr(PHP_OS, 'LINUX')) { $fh = \fopen('/proc/meminfo', 'r');
$fh = fopen('/proc/meminfo', 'r');
$mem = 0;
while ($line = fgets($fh)) { if ($fh === false) {
return $mem;
}
while ($line = \fgets($fh)) {
$pieces = []; $pieces = [];
if (\preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces)) { if (\preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces)) {
$mem = $pieces[1] * 1024; $mem = (int) ($pieces[1] ?? 0) * 1024;
break; break;
} }
} }
fclose($fh); \fclose($fh);
} }
return (int) $mem; return (int) $mem;
@ -81,12 +83,17 @@ final class SystemUtils
{ {
$memUsage = 0; $memUsage = 0;
if (stristr(PHP_OS, 'LINUX')) { if (\stristr(PHP_OS, 'LINUX')) {
$free = shell_exec('free'); $free = \shell_exec('free');
$free = (string) trim($free);
if ($free === null) {
return $memUsage;
}
$free = trim($free);
$freeArr = \explode("\n", $free); $freeArr = \explode("\n", $free);
$mem = \explode(" ", $freeArr[1]); $mem = \explode(' ', $freeArr[1]);
$mem = array_values(array_filter($mem)); $mem = \array_values(\array_filter($mem));
$memUsage = $mem[2] / $mem[1] * 100; $memUsage = $mem[2] / $mem[1] * 100;
} }
@ -104,11 +111,11 @@ final class SystemUtils
{ {
$cpuUsage = 0; $cpuUsage = 0;
if (stristr(PHP_OS, 'WIN') !== false) { if (\stristr(PHP_OS, 'WIN') !== false) {
$cpuUsage = null; $cpuUsage = null;
exec('wmic cpu get LoadPercentage', $cpuUsage); exec('wmic cpu get LoadPercentage', $cpuUsage);
$cpuUsage = $cpuUsage[1]; $cpuUsage = $cpuUsage[1];
} elseif (stristr(PHP_OS, 'LINUX') !== false) { } elseif (\stristr(PHP_OS, 'LINUX') !== false) {
$cpuUsage = \sys_getloadavg()[0] * 100; $cpuUsage = \sys_getloadavg()[0] * 100;
} }

View File

@ -61,14 +61,14 @@ final class UnhandledHandler
{ {
$logger = FileLogger::getInstance(__DIR__ . '/../Logs'); $logger = FileLogger::getInstance(__DIR__ . '/../Logs');
if (!(error_reporting() & $errno)) { if (!(\error_reporting() & $errno)) {
$logger->error(FileLogger::MSG_FULL, [ $logger->error(FileLogger::MSG_FULL, [
'message' => 'Undefined error', 'message' => 'Undefined error',
'line' => $errline, 'line' => $errline,
'file' => $errfile, 'file' => $errfile,
]); ]);
error_clear_last(); \error_clear_last();
return false; return false;
} }
@ -80,7 +80,7 @@ final class UnhandledHandler
'file' => $errfile, 'file' => $errfile,
]); ]);
error_clear_last(); \error_clear_last();
return true; return true;
} }
@ -95,9 +95,9 @@ final class UnhandledHandler
*/ */
public static function shutdownHandler() : void public static function shutdownHandler() : void
{ {
$e = error_get_last(); $e = \error_get_last();
if (isset($e)) { if ($e !== null) {
$logger = FileLogger::getInstance(__DIR__ . '/../Logs'); $logger = FileLogger::getInstance(__DIR__ . '/../Logs');
$logger->warning(FileLogger::MSG_FULL, [ $logger->warning(FileLogger::MSG_FULL, [
'message' => $e['message'], 'message' => $e['message'],

326
Uri/Argument.php Normal file
View File

@ -0,0 +1,326 @@
<?php
/**
* Orange Management
*
* PHP Version 7.2
*
* @package phpOMS\Uri
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link http://website.orange-management.de
*/
declare(strict_types=1);
namespace phpOMS\Uri;
use phpOMS\Utils\StringUtils;
/**
* Uri interface.
*
* Used in order to create and evaluate a uri
*
* @package phpOMS\Uri
* @license OMS License 1.0
* @link http://website.orange-management.de
* @since 1.0.0
*
* @SuppressWarnings(PHPMD.Superglobals)
*/
final class Argument implements UriInterface
{
/**
* Root path.
*
* @var string
* @since 1.0.0
*/
private $rootPath = '/';
/**
* Uri.
*
* @var string
* @since 1.0.0
*/
private $uri = '';
/**
* Uri scheme.
*
* @var string
* @since 1.0.0
*/
private $scheme = '';
/**
* Uri host.
*
* @var string
* @since 1.0.0
*/
private $host = '';
/**
* Uri port.
*
* @var int
* @since 1.0.0
*/
private $port = 80;
/**
* Uri user.
*
* @var string
* @since 1.0.0
*/
private $user = '';
/**
* Uri password.
*
* @var string
* @since 1.0.0
*/
private $pass = '';
/**
* Uri path.
*
* @var string
* @since 1.0.0
*/
private $path = '';
/**
* Uri query.
*
* @var array
* @since 1.0.0
*/
private $query = [];
/**
* Uri query.
*
* @var string
* @since 1.0.0
*/
private $queryString = '';
/**
* Uri fragment.
*
* @var string
* @since 1.0.0
*/
private $fragment = '';
/**
* Uri base.
*
* @var string
* @since 1.0.0
*/
private $base = '';
/**
* Constructor.
*
* @param string $uri Root path for subdirectory
*
* @since 1.0.0
*/
public function __construct(string $uri)
{
$this->set($uri);
}
/**
* {@inheritdoc}
*/
public function set(string $uri) : void
{
$this->uri = $uri;
$temp = $this->__toString();
$found = \stripos($temp, ':');
$path = $found !== false && $found > 3 && $found < 8 ? \substr($temp, $found) : $temp;
$this->path = $path === false ? '' : $path;
}
/**
* {@inheritdoc}
*/
public static function isValid(string $uri) : bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function getRootPath() : string
{
return $this->rootPath;
}
/**
* {@inheritdoc}
*/
public function setRootPath(string $root) : void
{
$this->rootPath = $root;
$this->set($this->uri);
}
/**
* {@inheritdoc}
*/
public function getScheme() : string
{
return $this->scheme;
}
/**
* {@inheritdoc}
*/
public function getHost() : string
{
return $this->host;
}
/**
* {@inheritdoc}
*/
public function getPort() : int
{
return $this->port;
}
/**
* {@inheritdoc}
*/
public function getPass() : string
{
return $this->pass;
}
/**
* {@inheritdoc}
*/
public function getPath() : string
{
return $this->path;
}
/**
* Get path offset.
*
* @return int
*
* @since 1.0.0
*/
public function getPathOffset() : int
{
return \substr_count($this->rootPath, '/') - 1;
}
/**
* {@inheritdoc}
*/
public function getRoute() : string
{
$query = $this->getQuery();
return $this->path . (!empty($query) ? '?' . $this->getQuery() : '');
}
/**
* {@inheritdoc}
*/
public function getQuery(string $key = null) : string
{
if ($key !== null) {
$key = \strtolower($key);
return $this->query[$key] ?? '';
}
return $this->queryString;
}
/**
* {@inheritdoc}
*/
public function getPathElement(int $pos = null) : string
{
return explode('/', $this->path)[$pos] ?? '';
}
/**
* {@inheritdoc}
*/
public function getPathElements() : array
{
return explode('/', $this->path);
}
/**
* {@inheritdoc}
*/
public function getQueryArray() : array
{
return $this->query;
}
/**
* {@inheritdoc}
*/
public function getFragment() : string
{
return $this->fragment;
}
/**
* {@inheritdoc}
*/
public function getBase() : string
{
return $this->base;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->uri;
}
/**
* {@inheritdoc}
*/
public function getAuthority() : string
{
return '';
}
/**
* {@inheritdoc}
*/
public function getUser() : string
{
return $this->user;
}
/**
* {@inheritdoc}
*/
public function getUserInfo() : string
{
return '';
}
}

View File

@ -145,7 +145,7 @@ final class Http implements UriInterface
public function set(string $uri) : void public function set(string $uri) : void
{ {
$this->uri = $uri; $this->uri = $uri;
$url = parse_url($this->uri); $url = \parse_url($this->uri);
$this->scheme = $url['scheme'] ?? ''; $this->scheme = $url['scheme'] ?? '';
$this->host = $url['host'] ?? ''; $this->host = $url['host'] ?? '';
@ -155,17 +155,23 @@ final class Http implements UriInterface
$this->path = $url['path'] ?? ''; $this->path = $url['path'] ?? '';
if (StringUtils::endsWith($this->path, '.php')) { if (StringUtils::endsWith($this->path, '.php')) {
$this->path = substr($this->path, 0, -4); $path = \substr($this->path, 0, -4);
if ($path === false) {
throw new \Exception();
}
$this->path = $path;
} }
$this->path = strpos($this->path, $this->rootPath) === 0 ? substr($this->path, strlen($this->rootPath), strlen($this->path)) : $this->path; $this->path = \strpos($this->path, $this->rootPath) === 0 ? \substr($this->path, \strlen($this->rootPath), \strlen($this->path)) : $this->path;
$this->queryString = $url['query'] ?? ''; $this->queryString = $url['query'] ?? '';
if (!empty($this->queryString)) { if (!empty($this->queryString)) {
parse_str($this->queryString, $this->query); \parse_str($this->queryString, $this->query);
} }
$this->query = array_change_key_case($this->query, CASE_LOWER); $this->query = \array_change_key_case($this->query, CASE_LOWER);
$this->fragment = $url['fragment'] ?? ''; $this->fragment = $url['fragment'] ?? '';
$this->base = $this->scheme . '://' . $this->host . $this->rootPath; $this->base = $this->scheme . '://' . $this->host . $this->rootPath;
@ -189,7 +195,7 @@ final class Http implements UriInterface
*/ */
public static function isValid(string $uri) : bool public static function isValid(string $uri) : bool
{ {
return (bool) filter_var($uri, FILTER_VALIDATE_URL); return (bool) \filter_var($uri, FILTER_VALIDATE_URL);
} }
/** /**
@ -258,7 +264,7 @@ final class Http implements UriInterface
*/ */
public function getPathOffset() : int public function getPathOffset() : int
{ {
return substr_count($this->rootPath, '/') - 1; return \substr_count($this->rootPath, '/') - 1;
} }
/** /**
@ -276,7 +282,7 @@ final class Http implements UriInterface
public function getQuery(string $key = null) : string public function getQuery(string $key = null) : string
{ {
if ($key !== null) { if ($key !== null) {
$key = strtolower($key); $key = \strtolower($key);
return $this->query[$key] ?? ''; return $this->query[$key] ?? '';
} }
@ -289,7 +295,7 @@ final class Http implements UriInterface
*/ */
public function getPathElement(int $pos = null) : string public function getPathElement(int $pos = null) : string
{ {
return explode('/', $this->path)[$pos] ?? ''; return \explode('/', $this->path)[$pos] ?? '';
} }
/** /**
@ -297,7 +303,7 @@ final class Http implements UriInterface
*/ */
public function getPathElements() : array public function getPathElements() : array
{ {
return explode('/', $this->path); return \explode('/', $this->path);
} }
/** /**

View File

@ -187,11 +187,10 @@ final class UriFactory
*/ */
private static function unique(string $url) : string private static function unique(string $url) : string
{ {
$parts = \explode('?', $url); $parts = \explode('&', \str_replace('?', '&', $url));
if (count($parts) >= 2) { if (count($parts) >= 2) {
$full = $parts[1]; $pars = \array_slice($parts, 1);
$pars = \explode('&', $full);
$comps = []; $comps = [];
$length = count($pars); $length = count($pars);

View File

@ -51,8 +51,11 @@ final class ArrayUtils
$nodes = \explode($delim, trim($path, $delim)); $nodes = \explode($delim, trim($path, $delim));
$prevEl = null; $prevEl = null;
$el = &$data; $el = &$data;
$node = null;
$node = null; if ($nodes === false) {
throw new \Exception();
}
foreach ($nodes as &$node) { foreach ($nodes as &$node) {
$prevEl = &$el; $prevEl = &$el;
@ -89,6 +92,10 @@ final class ArrayUtils
$pathParts = \explode($delim, trim($path, $delim)); $pathParts = \explode($delim, trim($path, $delim));
$current = &$data; $current = &$data;
if ($pathParts === false) {
throw new \Exception();
}
foreach ($pathParts as $key) { foreach ($pathParts as $key) {
$current = &$current[$key]; $current = &$current[$key];
} }
@ -124,6 +131,10 @@ final class ArrayUtils
$pathParts = \explode($delim, trim($path, $delim)); $pathParts = \explode($delim, trim($path, $delim));
$current = $data; $current = $data;
if ($pathParts === false) {
throw new \Exception();
}
foreach ($pathParts as $key) { foreach ($pathParts as $key) {
if (!isset($current[$key])) { if (!isset($current[$key])) {
return null; return null;
@ -266,14 +277,19 @@ final class ArrayUtils
*/ */
public static function arrayToCsv(array $data, string $delimiter = ';', string $enclosure = '"', string $escape = '\\') : string public static function arrayToCsv(array $data, string $delimiter = ';', string $enclosure = '"', string $escape = '\\') : string
{ {
$outstream = fopen('php://memory', 'r+'); $outstream = \fopen('php://memory', 'r+');
/** @noinspection PhpMethodParametersCountMismatchInspection */
fputcsv($outstream, $data, $delimiter, $enclosure, $escape);
rewind($outstream);
$csv = fgets($outstream);
fclose($outstream);
return $csv; if ($outstream === false) {
throw new \Exception();
}
/** @noinspection PhpMethodParametersCountMismatchInspection */
\fputcsv($outstream, $data, $delimiter, $enclosure, $escape);
rewind($outstream);
$csv = \fgets($outstream);
\fclose($outstream);
return $csv === false ? '' : $csv;
} }
/** /**
@ -290,11 +306,11 @@ final class ArrayUtils
*/ */
public static function getArg(string $id, array $args) : ?string public static function getArg(string $id, array $args) : ?string
{ {
if (($key = array_search($id, $args)) === false || $key === count($args) - 1) { if (($key = \array_search($id, $args)) === false || $key === count($args) - 1) {
return null; return null;
} }
return trim($args[$key + 1], '" '); return trim($args[(int) $key + 1], '" ');
} }
/** /**
@ -309,11 +325,11 @@ final class ArrayUtils
*/ */
public static function hasArg(string $id, array $args) : ?int public static function hasArg(string $id, array $args) : ?int
{ {
if (($key = array_search($id, $args)) === false) { if (($key = \array_search($id, $args)) === false) {
return null; return null;
} }
return $key; return (int) $key;
} }
/** /**

View File

@ -147,11 +147,11 @@ abstract class C128Abstract
public function setDimension(int $width, int $height) : void public function setDimension(int $width, int $height) : void
{ {
if ($width < 0) { if ($width < 0) {
throw new \OutOfBoundsException($width); throw new \OutOfBoundsException((string) $width);
} }
if ($height < 0) { if ($height < 0) {
throw new \OutOfBoundsException($height); throw new \OutOfBoundsException((string) $height);
} }
$this->dimension['width'] = $width; $this->dimension['width'] = $width;
@ -243,8 +243,8 @@ abstract class C128Abstract
{ {
$res = $this->get(); $res = $this->get();
imagepng($res, $file); \imagepng($res, $file);
imagedestroy($res); \imagedestroy($res);
} }
/** /**
@ -260,8 +260,8 @@ abstract class C128Abstract
{ {
$res = $this->get(); $res = $this->get();
imagejpeg($res, $file); \imagejpeg($res, $file);
imagedestroy($res); \imagedestroy($res);
} }
/** /**
@ -273,14 +273,14 @@ abstract class C128Abstract
*/ */
protected function generateCodeString() : string protected function generateCodeString() : string
{ {
$keys = array_keys(static::$CODEARRAY); $keys = \array_keys(static::$CODEARRAY);
$values = array_flip($keys); $values = \array_flip($keys);
$codeString = ''; $codeString = '';
$length = strlen($this->content); $length = \strlen($this->content);
$checksum = static::$CHECKSUM; $checksum = static::$CHECKSUM;
for ($pos = 1; $pos <= $length; $pos++) { for ($pos = 1; $pos <= $length; $pos++) {
$activeKey = substr($this->content, ($pos - 1), 1); $activeKey = \substr($this->content, ($pos - 1), 1);
$codeString .= static::$CODEARRAY[$activeKey]; $codeString .= static::$CODEARRAY[$activeKey];
$checksum += $values[$activeKey] * $pos; $checksum += $values[$activeKey] * $pos;
} }
@ -302,18 +302,23 @@ abstract class C128Abstract
protected function createImage(string $codeString) protected function createImage(string $codeString)
{ {
$dimensions = $this->calculateDimensions($codeString); $dimensions = $this->calculateDimensions($codeString);
$image = imagecreate($dimensions['width'], $dimensions['height']); $image = \imagecreate($dimensions['width'], $dimensions['height']);
$black = imagecolorallocate($image, 0, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255); if ($image === false) {
throw new \Exception();
}
$black = \imagecolorallocate($image, 0, 0, 0);
$white = \imagecolorallocate($image, 255, 255, 255);
$location = 0; $location = 0;
$length = strlen($codeString); $length = \strlen($codeString);
imagefill($image, 0, 0, $white); \imagefill($image, 0, 0, $white);
for ($position = 1; $position <= $length; $position++) { for ($position = 1; $position <= $length; $position++) {
$cur_size = $location + (int) (substr($codeString, ($position - 1), 1)); $cur_size = $location + (int) (\substr($codeString, ($position - 1), 1));
if ($this->orientation === OrientationType::HORIZONTAL) { if ($this->orientation === OrientationType::HORIZONTAL) {
imagefilledrectangle( \imagefilledrectangle(
$image, $image,
$location + $this->margin, $location + $this->margin,
0 + $this->margin, 0 + $this->margin,
@ -322,7 +327,7 @@ abstract class C128Abstract
($position % 2 == 0 ? $white : $black) ($position % 2 == 0 ? $white : $black)
); );
} else { } else {
imagefilledrectangle( \imagefilledrectangle(
$image, $image,
0 + $this->margin, 0 + $this->margin,
$location + $this->margin, $location + $this->margin,
@ -350,10 +355,10 @@ abstract class C128Abstract
private function calculateCodeLength(string $codeString) : int private function calculateCodeLength(string $codeString) : int
{ {
$codeLength = 0; $codeLength = 0;
$length = strlen($codeString); $length = \strlen($codeString);
for ($i = 1; $i <= $length; ++$i) { for ($i = 1; $i <= $length; ++$i) {
$codeLength = $codeLength + (int) (substr($codeString, ($i - 1), 1)); $codeLength = $codeLength + (int) (\substr($codeString, ($i - 1), 1));
} }
return $codeLength; return $codeLength;

View File

@ -39,17 +39,17 @@ class LZW implements CompressionInterface
$dictionary[chr($i)] = $i; $dictionary[chr($i)] = $i;
} }
$length = strlen($source); $length = \strlen($source);
for ($i = 0; $i < $length; ++$i) { for ($i = 0; $i < $length; ++$i) {
$c = $source[$i]; $c = $source[$i];
$wc = $w . $c; $wc = $w . $c;
if (array_key_exists($w . $c, $dictionary)) { if (\array_key_exists($w . $c, $dictionary)) {
$w = $w . $c; $w = $w . $c;
} else { } else {
$result[] = $dictionary[$w]; $result[] = $dictionary[$w];
$dictionary[$wc] = $dictSize++; $dictionary[$wc] = $dictSize++;
$w = (string) $c; $w = $c;
} }
} }
@ -57,7 +57,7 @@ class LZW implements CompressionInterface
$result[] = $dictionary[$w]; $result[] = $dictionary[$w];
} }
return implode(',', $result); return \implode(',', $result);
} }
/** /**
@ -70,16 +70,20 @@ class LZW implements CompressionInterface
$entry = ''; $entry = '';
$dictSize = 256; $dictSize = 256;
if (empty($compressed)) {
return '';
}
for ($i = 0; $i < 256; ++$i) { for ($i = 0; $i < 256; ++$i) {
$dictionary[$i] = chr($i); $dictionary[$i] = chr($i);
} }
$w = chr($compressed[0]); $w = chr((int) $compressed[0]);
$result = $dictionary[$compressed[0]]; $result = $dictionary[(int) ($compressed[0])] ?? 0;
$count = count($compressed); $count = count($compressed);
for ($i = 1; $i < $count; ++$i) { for ($i = 1; $i < $count; ++$i) {
$k = $compressed[$i]; $k = (int) $compressed[$i];
if ($dictionary[$k]) { if ($dictionary[$k]) {
$entry = $dictionary[$k]; $entry = $dictionary[$k];

View File

@ -49,6 +49,9 @@ class Ip
{ {
$split = \explode('.', $ip); $split = \explode('.', $ip);
return $split[0] * (256 ** 3) + $split[1] * (256 ** 2) + $split[2] * (256 ** 1) + $split[3]; return ((int) $split[0] ?? 0) * (256 ** 3)
+ ((int) $split[1] ?? 0) * (256 ** 2)
+ ((int) $split[2] ?? 0) * (256 ** 1)
+ ((int) $split[3] ?? 0);
} }
} }

View File

@ -64,22 +64,26 @@ class Numeric
return $numberInput; return $numberInput;
} }
$fromBase = str_split($fromBaseInput, 1); $fromBase = \str_split($fromBaseInput, 1);
$toBase = str_split($toBaseInput, 1); $toBase = \str_split($toBaseInput, 1);
$number = str_split($numberInput, 1); $number = \str_split($numberInput, 1);
$fromLen = strlen($fromBaseInput); $fromLen = \strlen($fromBaseInput);
$toLen = strlen($toBaseInput); $toLen = \strlen($toBaseInput);
$numberLen = strlen($numberInput); $numberLen = \strlen($numberInput);
$newOutput = ''; $newOutput = '';
if ($fromBase === false || $toBase === false || $number === false) {
throw new \Exception();
}
if ($toBaseInput === '0123456789') { if ($toBaseInput === '0123456789') {
$newOutput = 0; $newOutput = '0';
for ($i = 1; $i <= $numberLen; ++$i) { for ($i = 1; $i <= $numberLen; ++$i) {
$newOutput = bcadd( $newOutput = bcadd(
(string) $newOutput, $newOutput,
bcmul( bcmul(
(string) array_search($number[$i - 1], $fromBase), (string) \array_search($number[$i - 1], $fromBase),
bcpow((string) $fromLen, (string) ($numberLen - $i)) bcpow((string) $fromLen, (string) ($numberLen - $i))
) )
); );
@ -88,15 +92,15 @@ class Numeric
return $newOutput; return $newOutput;
} }
$base10 = $fromBaseInput != '0123456789' ? self::convertBase($numberInput, $fromBaseInput, '0123456789') : $numberInput; $base10 = (int) ($fromBaseInput != '0123456789' ? self::convertBase($numberInput, $fromBaseInput, '0123456789') : $numberInput);
if ($base10 < strlen($toBaseInput)) { if ($base10 < \strlen($toBaseInput)) {
return $toBase[$base10]; return $toBase[$base10];
} }
while ($base10 !== '0') { while ($base10 !== '0') {
$newOutput = $toBase[bcmod($base10, (string) $toLen)] . $newOutput; $newOutput = $toBase[(int) bcmod((string) $base10, (string) $toLen)] . $newOutput;
$base10 = bcdiv($base10, (string) $toLen, 0); $base10 = bcdiv((string) $base10, (string) $toLen, 0);
} }
return $newOutput; return $newOutput;
@ -144,9 +148,13 @@ class Numeric
$result = 0; $result = 0;
foreach (self::ROMANS as $key => $value) { foreach (self::ROMANS as $key => $value) {
while (strpos($roman, $key) === 0) { while (\strpos($roman, $key) === 0) {
$result += $value; $result += $value;
$roman = substr($roman, strlen($key)); $temp = \substr($roman, \strlen($key));
if ($temp !== false) {
$roman = $temp;
}
} }
} }
@ -169,7 +177,7 @@ class Numeric
$alpha = ''; $alpha = '';
for ($i = 1; $number >= 0 && $i < 10; ++$i) { for ($i = 1; $number >= 0 && $i < 10; ++$i) {
$alpha = chr(0x41 + ($number % pow(26, $i) / pow(26, $i - 1))) . $alpha; $alpha = chr(0x41 + (int) ($number % pow(26, $i) / pow(26, $i - 1))) . $alpha;
$number -= pow(26, $i); $number -= pow(26, $i);
} }
@ -188,12 +196,12 @@ class Numeric
public static function alphaToNumeric(string $alpha) : int public static function alphaToNumeric(string $alpha) : int
{ {
$numeric = 0; $numeric = 0;
$length = strlen($alpha); $length = \strlen($alpha);
for ($i = 0; $i < $length; ++$i) { for ($i = 0; $i < $length; ++$i) {
$numeric += pow(26, $i) * (ord($alpha[$length - $i - 1]) - 0x40); $numeric += pow(26, $i) * (ord($alpha[$length - $i - 1]) - 0x40);
} }
return $numeric - 1; return (int) $numeric - 1;
} }
} }

View File

@ -82,11 +82,15 @@ final class Huffman
$binary .= $this->dictionary->get($source[$i]); $binary .= $this->dictionary->get($source[$i]);
} }
$splittedBinaryString = str_split('1' . $binary . '1', 8); $splittedBinaryString = \str_split('1' . $binary . '1', 8);
$binary = ''; $binary = '';
if ($splittedBinaryString === false) {
return $binary;
}
foreach ($splittedBinaryString as $i => $c) { foreach ($splittedBinaryString as $i => $c) {
while (strlen($c) < 8) { while (\strlen($c) < 8) {
$c .= '0'; $c .= '0';
} }
@ -112,22 +116,40 @@ final class Huffman
} }
$binary = ''; $binary = '';
$rawLenght = strlen($raw); $rawLenght = \strlen($raw);
$source = ''; $source = '';
for ($i = 0; $i < $rawLenght; ++$i) { for ($i = 0; $i < $rawLenght; ++$i) {
$decbin = decbin(ord($raw[$i])); $decbin = decbin(ord($raw[$i]));
while (strlen($decbin) < 8) { while (\strlen($decbin) < 8) {
$decbin = '0' . $decbin; $decbin = '0' . $decbin;
} }
if ($i === 0) { if ($i === 0) {
$decbin = substr($decbin, strpos($decbin, '1') + 1); $pos = \strpos($decbin, '1');
if ($pos === false) {
throw new \Exception();
}
$decbin = \substr($decbin, $pos + 1);
if ($decbin === false) {
throw new \Exception();
}
} }
if ($i + 1 === $rawLenght) { if ($i + 1 === $rawLenght) {
$decbin = substr($decbin, 0, strrpos($decbin, '1')); $pos = \strrpos($decbin, '1');
if ($pos === false) {
throw new \Exception();
}
$decbin = \substr($decbin, 0, $pos);
if ($decbin === false) {
throw new \Exception();
}
} }
$binary .= $decbin; $binary .= $decbin;

View File

@ -101,7 +101,7 @@ class Commit
$this->author = new Author(); $this->author = new Author();
$this->branch = new Branch(); $this->branch = new Branch();
$this->tag = new Tag(); $this->tag = new Tag();
$this->repository = new Repository(realpath(__DIR__ . '/../../../../../')); $this->repository = new Repository();
} }
/** /**

View File

@ -45,16 +45,16 @@ class Git
public static function test() : bool public static function test() : bool
{ {
$pipes = []; $pipes = [];
$resource = proc_open(escapeshellarg(Git::getBin()), [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); $resource = \proc_open(\escapeshellarg(Git::getBin()), [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
$stdout = stream_get_contents($pipes[1]); $stdout = \stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]); $stderr = \stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) { foreach ($pipes as $pipe) {
fclose($pipe); \fclose($pipe);
} }
return trim(proc_close($resource)) !== 127; return $resource !== false && \proc_close($resource) !== 127;
} }
/** /**
@ -82,10 +82,10 @@ class Git
*/ */
public static function setBin(string $path) : void public static function setBin(string $path) : void
{ {
if (realpath($path) === false) { if (\realpath($path) === false) {
throw new PathException($path); throw new PathException($path);
} }
self::$bin = realpath($path); self::$bin = \realpath($path);
} }
} }

Some files were not shown because too many files have changed in this diff Show More