diff --git a/.gitignore b/.gitignore
index bf0824e59..954fa8953 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
-*.log
\ No newline at end of file
+*.log
+.directory
+vendor
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..857485eed
--- /dev/null
+++ b/.travis.yml
@@ -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
\ No newline at end of file
diff --git a/Account/Account.php b/Account/Account.php
index 597ea510c..5c53f8cc7 100644
--- a/Account/Account.php
+++ b/Account/Account.php
@@ -453,11 +453,11 @@ class Account implements ArrayableInterface, \JsonSerializable
*/
public function setEmail(string $email) : void
{
- if (!Email::isValid($email)) {
+ if ($email !== '' && !Email::isValid($email)) {
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
{
- $this->password = \password_hash($password, \PASSWORD_DEFAULT);
+ $temp = \password_hash($password, \PASSWORD_DEFAULT);
- if ($this->password === false) {
+ if ($temp === false) {
throw new \Exception();
}
+
+ $this->password = $temp;
}
/**
@@ -603,7 +605,7 @@ class Account implements ArrayableInterface, \JsonSerializable
*/
public function __toString() : string
{
- return \json_encode($this->toArray());
+ return (string) \json_encode($this->toArray());
}
/**
diff --git a/Account/Group.php b/Account/Group.php
index 8bcd3e429..a22a52e2d 100644
--- a/Account/Group.php
+++ b/Account/Group.php
@@ -189,7 +189,7 @@ class Group implements ArrayableInterface, \JsonSerializable
*/
public function __toString() : string
{
- return \json_encode($this->toArray());
+ return (string) \json_encode($this->toArray());
}
/**
diff --git a/ApplicationAbstract.php b/ApplicationAbstract.php
index 5bddb2f24..9a134a294 100644
--- a/ApplicationAbstract.php
+++ b/ApplicationAbstract.php
@@ -22,6 +22,7 @@ namespace phpOMS;
* and afterwards read only.
*
* @property string $appName
+ * @property int $orgId
* @property \phpOMS\DataStorage\Database\DatabasePool $dbPool
* @property \phpOMS\Localization\L11nManager $l11nManager
* @property \phpOMS\Router\Router $router
@@ -50,6 +51,14 @@ class ApplicationAbstract
*/
protected $appName = '';
+ /**
+ * Organization id.
+ *
+ * @var int
+ * @since 1.0.0
+ */
+ protected $orgId = 1;
+
/**
* Database object.
*
diff --git a/Autoloader.php b/Autoloader.php
index 9ee328ee4..d05b6c2d0 100644
--- a/Autoloader.php
+++ b/Autoloader.php
@@ -81,7 +81,7 @@ final class Autoloader
$class = \str_replace(['_', '\\'], '/', $class);
foreach (self::$paths as $path) {
- if (file_exists($file = $path . $class . '.php')) {
+ if (\file_exists($file = $path . $class . '.php')) {
include_once $file;
return;
@@ -106,7 +106,7 @@ final class Autoloader
$class = \str_replace(['_', '\\'], '/', $class);
foreach (self::$paths as $path) {
- if (file_exists($file = $path . $class . '.php')) {
+ if (\file_exists($file = $path . $class . '.php')) {
return true;
}
}
diff --git a/Business/Finance/FinanceFormulas.php b/Business/Finance/FinanceFormulas.php
index ba21fee44..3f80c7ef3 100644
--- a/Business/Finance/FinanceFormulas.php
+++ b/Business/Finance/FinanceFormulas.php
@@ -48,7 +48,7 @@ final class FinanceFormulas
*/
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
{
- 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
{
- return (float) pow(1 + $r, $n);
+ return pow(1 + $r, $n);
}
/**
diff --git a/Business/Finance/StockBonds.php b/Business/Finance/StockBonds.php
index 40ae2024a..54f6d1721 100644
--- a/Business/Finance/StockBonds.php
+++ b/Business/Finance/StockBonds.php
@@ -369,6 +369,6 @@ final class StockBonds
*/
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;
}
}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b0f7afa67..8b995dab4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,27 +1,27 @@
-# Contributing
-
-## Code Style & Best Practices
-
-For the code style and best practices please have a look at the developer-guide [https://github.com/Orange-Management/Developer-Guide](https://github.com/Orange-Management/Developer-Guide). Especially the `standards` should be followed for a successful pull request.
-
-## How Can I Contribute
-
-### Suggestions
-
-If you have a good idea for improvement feel free to create a new issue with all the relevant information.
-
-### Issues
-
-Feel free to grab any open issue implement it and create a new pull request.
-
-### Code Style
-
-Not always are the defined coding style standards upheld, if you notice that simply create a new pull request with the fix.
-
-### Code Coverage
-
-While code coverage is just a metric it is still appreciated to cover as many files and code paths as possible. Just have a look at the code coverage and implement missing unit tests.
-
-### Freatures
-
+# Contributing
+
+## Code Style & Best Practices
+
+For the code style and best practices please have a look at the developer-guide [https://github.com/Orange-Management/Developer-Guide](https://github.com/Orange-Management/Developer-Guide). Especially the `standards` should be followed for a successful pull request.
+
+## How Can I Contribute
+
+### Suggestions
+
+If you have a good idea for improvement feel free to create a new issue with all the relevant information.
+
+### Issues
+
+Feel free to grab any open issue implement it and create a new pull request.
+
+### Code Style
+
+Not always are the defined coding style standards upheld, if you notice that simply create a new pull request with the fix.
+
+### Code Coverage
+
+While code coverage is just a metric it is still appreciated to cover as many files and code paths as possible. Just have a look at the code coverage and implement missing unit tests.
+
+### Freatures
+
You have a good idea for a feature and can implement it yourself, go ahead and create a new pull request.
\ No newline at end of file
diff --git a/Config/SettingsAbstract.php b/Config/SettingsAbstract.php
index 042805f76..f23ecd39a 100644
--- a/Config/SettingsAbstract.php
+++ b/Config/SettingsAbstract.php
@@ -105,6 +105,11 @@ abstract class SettingsAbstract implements OptionsInterface
$sth->execute();
$options = $sth->fetchAll(\PDO::FETCH_KEY_PAIR);
+
+ if ($options === false) {
+ return [];
+ }
+
$this->setOptions($options);
break;
}
diff --git a/Console/CommandManager.php b/Console/CommandManager.php
deleted file mode 100644
index a76251c97..000000000
--- a/Console/CommandManager.php
+++ /dev/null
@@ -1,129 +0,0 @@
-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;
- }
-}
diff --git a/DataStorage/Cache/Connection/ConnectionAbstract.php b/DataStorage/Cache/Connection/ConnectionAbstract.php
index 8f5135a82..8baac3b3b 100644
--- a/DataStorage/Cache/Connection/ConnectionAbstract.php
+++ b/DataStorage/Cache/Connection/ConnectionAbstract.php
@@ -15,6 +15,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Cache\Connection;
use phpOMS\DataStorage\Cache\CacheStatus;
+use phpOMS\DataStorage\Cache\CacheType;
/**
* Cache handler.
@@ -38,7 +39,7 @@ abstract class ConnectionAbstract implements ConnectionInterface
* @var mixed
* @since 1.0.0
*/
- private $con = null;
+ protected $con = null;
/**
* Database prefix.
@@ -64,7 +65,7 @@ abstract class ConnectionAbstract implements ConnectionInterface
* @var string
* @since 1.0.0
*/
- protected $type = CacheStatus::UNDEFINED;
+ protected $type = CacheType::UNDEFINED;
/**
* Database status.
diff --git a/DataStorage/Cache/Connection/FileCache.php b/DataStorage/Cache/Connection/FileCache.php
index e924953d2..2ba18837d 100644
--- a/DataStorage/Cache/Connection/FileCache.php
+++ b/DataStorage/Cache/Connection/FileCache.php
@@ -218,7 +218,7 @@ class FileCache extends ConnectionAbstract
if ($type === CacheValueType::_INT || $type === CacheValueType::_FLOAT || $type === CacheValueType::_STRING || $type === CacheValueType::_BOOL) {
return (string) $value;
} elseif ($type === CacheValueType::_ARRAY) {
- return \json_encode($value);
+ return (string) \json_encode($value);
} elseif ($type === CacheValueType::_SERIALIZABLE) {
return \get_class($value) . self::DELIM . $value->serialize();
} elseif ($type === CacheValueType::_JSONSERIALIZABLE) {
@@ -241,8 +241,8 @@ class FileCache extends ConnectionAbstract
*/
private function getExpire(string $raw) : int
{
- $expireStart = \strpos($raw, self::DELIM);
- $expireEnd = \strpos($raw, self::DELIM, $expireStart + 1);
+ $expireStart = (int) \strpos($raw, self::DELIM);
+ $expireEnd = (int) \strpos($raw, self::DELIM, $expireStart + 1);
return (int) \substr($raw, $expireStart + 1, $expireEnd - ($expireStart + 1));
}
@@ -257,7 +257,6 @@ class FileCache extends ConnectionAbstract
}
$path = $this->getPath($key);
-
if (!File::exists($path)) {
return null;
}
@@ -269,12 +268,21 @@ class FileCache extends ConnectionAbstract
return null;
}
- $raw = File::get($path);
- $type = (int) $raw[0];
+ $raw = \file_get_contents($path);
+ 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 = ($cacheExpire === false) ? $created : (int) $cacheExpire;
if ($cacheExpire >= 0 && $created + $cacheExpire < $now) {
$this->delete($key);
@@ -314,18 +322,23 @@ class FileCache extends ConnectionAbstract
$value = \substr($raw, $expireEnd + 1);
break;
case CacheValueType::_ARRAY:
- $value = \json_decode(substr($raw, $expireEnd + 1));
+ $array = \substr($raw, $expireEnd + 1);
+ $value = \json_decode($array === false ? '[]' : $array, true);
break;
case CacheValueType::_NULL:
$value = null;
break;
case CacheValueType::_SERIALIZABLE:
case CacheValueType::_JSONSERIALIZABLE:
- $namespaceStart = \strpos($raw, self::DELIM, $expireEnd);
- $namespaceEnd = \strpos($raw, self::DELIM, $namespaceStart + 1);
+ $namespaceStart = (int) \strpos($raw, self::DELIM, $expireEnd);
+ $namespaceEnd = (int) \strpos($raw, self::DELIM, $namespaceStart + 1);
$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;
}
@@ -342,7 +355,6 @@ class FileCache extends ConnectionAbstract
}
$path = $this->getPath($key);
-
if ($expire < 0 && File::exists($path)) {
File::delete($path);
@@ -350,12 +362,29 @@ class FileCache extends ConnectionAbstract
}
if ($expire >= 0) {
- $created = Directory::created(Directory::sanitize($key, self::SANITIZE))->getTimestamp();
- $now = \time();
- $raw = \file_get_contents($path);
- $expireStart = \strpos($raw, self::DELIM);
- $expireEnd = \strpos($raw, self::DELIM, $expireStart + 1);
+ $created = Directory::created(Directory::sanitize($key, self::SANITIZE))->getTimestamp();
+ $now = \time();
+ $raw = \file_get_contents($path);
+
+ 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 = ($cacheExpire === false) ? $created : (int) $cacheExpire;
+
+ if ($cacheExpire >= 0 && $created + $cacheExpire < $now) {
+ $this->delete($key);
+
+ return false;
+ }
if ($cacheExpire >= 0 && $created + $cacheExpire > $now) {
File::delete($path);
diff --git a/DataStorage/DataStorageConnectionInterface.php b/DataStorage/DataStorageConnectionInterface.php
index 3f79866a3..a69f3421e 100644
--- a/DataStorage/DataStorageConnectionInterface.php
+++ b/DataStorage/DataStorageConnectionInterface.php
@@ -25,6 +25,15 @@ namespace phpOMS\DataStorage;
interface DataStorageConnectionInterface
{
+ /**
+ * Get prefix.
+ *
+ * @return string
+ *
+ * @since 1.0.0
+ */
+ public function getPrefix() : string;
+
/**
* Connect to datastorage.
*
diff --git a/DataStorage/DataStoragePoolInterface.php b/DataStorage/DataStoragePoolInterface.php
index bc3bd597f..d55c14d72 100644
--- a/DataStorage/DataStoragePoolInterface.php
+++ b/DataStorage/DataStoragePoolInterface.php
@@ -44,7 +44,7 @@ interface DataStoragePoolInterface
*
* @param string $key Connection key
*
- * @return mixed
+ * @return DataStorageConnectionInterface
*
* @since 1.0.0
*/
diff --git a/DataStorage/Database/BuilderAbstract.php b/DataStorage/Database/BuilderAbstract.php
index f5f81816b..e391224ab 100644
--- a/DataStorage/Database/BuilderAbstract.php
+++ b/DataStorage/Database/BuilderAbstract.php
@@ -14,7 +14,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database;
-use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
+use phpOMS\DataStorage\DataStorageConnectionInterface;
use phpOMS\DataStorage\Database\Query\QueryType;
/**
@@ -38,7 +38,7 @@ abstract class BuilderAbstract
/**
* Database connection.
*
- * @var ConnectionAbstract
+ * @var DataStorageConnectionInterface
* @since 1.0.0
*/
protected $connection = null;
@@ -49,7 +49,7 @@ abstract class BuilderAbstract
* @var int
* @since 1.0.0
*/
- protected $type = QueryType::EMPTY;
+ protected $type = QueryType::NONE;
/**
* Prefix.
@@ -68,15 +68,9 @@ abstract class BuilderAbstract
public $raw = '';
/**
- * Set prefix.
- *
- * @param string $prefix Prefix
- *
- * @return BuilderAbstract
- *
- * @since 1.0.0
+ * {@inheritdoc}
*/
- public function prefix(string $prefix) : BuilderAbstract
+ public function prefix(string $prefix) : self
{
$this->prefix = $prefix;
diff --git a/DataStorage/Database/Connection/ConnectionFactory.php b/DataStorage/Database/Connection/ConnectionFactory.php
index 06016d28d..3d89957ea 100644
--- a/DataStorage/Database/Connection/ConnectionFactory.php
+++ b/DataStorage/Database/Connection/ConnectionFactory.php
@@ -44,13 +44,13 @@ final class ConnectionFactory
*
* @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.
*
* @since 1.0.0
*/
- public static function create(array $dbdata) : ConnectionInterface
+ public static function create(array $dbdata) : ConnectionAbstract
{
switch ($dbdata['db']) {
case DatabaseType::MYSQL:
diff --git a/DataStorage/Database/Connection/MysqlConnection.php b/DataStorage/Database/Connection/MysqlConnection.php
index a05fc19b3..92676ab56 100644
--- a/DataStorage/Database/Connection/MysqlConnection.php
+++ b/DataStorage/Database/Connection/MysqlConnection.php
@@ -59,7 +59,7 @@ final class MysqlConnection extends ConnectionAbstract
$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'])) {
- throw new InvalidConnectionConfigException(\json_encode($this->dbdata));
+ throw new InvalidConnectionConfigException((string) \json_encode($this->dbdata));
}
$this->close();
diff --git a/DataStorage/Database/Connection/PostgresConnection.php b/DataStorage/Database/Connection/PostgresConnection.php
index 33fa94d48..ae61b9338 100644
--- a/DataStorage/Database/Connection/PostgresConnection.php
+++ b/DataStorage/Database/Connection/PostgresConnection.php
@@ -58,7 +58,7 @@ final class PostgresConnection extends ConnectionAbstract
$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'])) {
- throw new InvalidConnectionConfigException(\json_encode($this->dbdata));
+ throw new InvalidConnectionConfigException((string) \json_encode($this->dbdata));
}
$this->close();
diff --git a/DataStorage/Database/Connection/SQLiteConnection.php b/DataStorage/Database/Connection/SQLiteConnection.php
index 5e45f345f..23374e332 100644
--- a/DataStorage/Database/Connection/SQLiteConnection.php
+++ b/DataStorage/Database/Connection/SQLiteConnection.php
@@ -16,7 +16,7 @@ namespace phpOMS\DataStorage\Database\Connection;
use phpOMS\DataStorage\Database\DatabaseStatus;
use phpOMS\DataStorage\Database\DatabaseType;
-use phpOMS\DataStorage\Database\Query\Grammar\SqliteGrammar;
+use phpOMS\DataStorage\Database\Query\Grammar\SQLiteGrammar;
/**
* Database handler.
@@ -29,7 +29,7 @@ use phpOMS\DataStorage\Database\Query\Grammar\SqliteGrammar;
* @link http://website.orange-management.de
* @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)
{
- $this->type = DatabaseType::MYSQL;
- $this->grammar = new SqliteGrammar();
+ $this->type = DatabaseType::SQLITE;
+ $this->grammar = new SQLiteGrammar();
$this->connect($dbdata);
}
@@ -65,9 +65,10 @@ final class SqliteConnection extends ConnectionAbstract
$this->status = DatabaseStatus::OK;
} catch (\PDOException $e) {
- var_dump($e->getMessage());
$this->status = DatabaseStatus::MISSING_DATABASE;
$this->con = null;
+ } finally {
+ $this->dbdata['password'] = '****';
}
}
}
diff --git a/DataStorage/Database/DataMapperAbstract.php b/DataStorage/Database/DataMapperAbstract.php
index bf0331ea1..ce749e46e 100644
--- a/DataStorage/Database/DataMapperAbstract.php
+++ b/DataStorage/Database/DataMapperAbstract.php
@@ -14,7 +14,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database;
-use phpOMS\DataStorage\DataStorageConnectionInterface;
+use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
use phpOMS\DataStorage\Database\Query\Builder;
use phpOMS\DataStorage\DataMapperInterface;
use phpOMS\Message\RequestAbstract;
@@ -37,7 +37,7 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Database connection.
*
- * @var DataStorageConnectionInterface
+ * @var ConnectionAbstract
* @since 1.0.0
*/
protected static $db = null;
@@ -149,7 +149,7 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Highest mapper to know when to clear initialized objects
*
- * @var string
+ * @var null|string
* @since 1.0.0
*/
protected static $parentMapper = null;
@@ -195,13 +195,13 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Set database connection.
*
- * @param DataStorageConnectionInterface $con Database connection
+ * @param ConnectionAbstract $con Database connection
*
* @return void
*
* @since 1.0.0
*/
- public static function setConnection(DataStorageConnectionInterface $con) : void
+ public static function setConnection(ConnectionAbstract $con) : void
{
self::$db = $con;
}
@@ -389,20 +389,20 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Create base model.
*
- * @param Object $obj Model to create
+ * @param object $obj Model to create
* @param \ReflectionClass $refClass Reflection class
*
* @return mixed
*
* @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->prefix(self::$db->getPrefix())->into(static::$table);
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])) {
continue;
}
@@ -425,11 +425,11 @@ class DataMapperAbstract implements DataMapperInterface
$query->insert($column['name'])->value($value, $column['type']);
} elseif ($column['name'] !== static::$primaryField) {
$tValue = $property->getValue($obj);
- if (stripos($column['internal'], '/') !== false) {
+ if (\stripos($column['internal'], '/') !== false) {
$path = \explode('/', $column['internal']);
- array_shift($path);
- $path = implode('/', $path);
+ \array_shift($path);
+ $path = \implode('/', $path);
$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 ($query->getType() === QueryType::EMPTY) {
+ if ($query->getType() === QueryType::NONE) {
$query->insert(static::$primaryField)->value(0, static::$columns[static::$primaryField]['type']);
}
@@ -475,11 +475,11 @@ class DataMapperAbstract implements DataMapperInterface
}
$path = $column['internal'];
- if (stripos($column['internal'], '/') !== false) {
+ if (\stripos($column['internal'], '/') !== false) {
$path = \explode('/', $column['internal']);
- array_shift($path);
- $path = implode('/', $path);
+ \array_shift($path);
+ $path = \implode('/', $path);
}
$property = ArrayUtils::getArray($path, $obj, '/');
@@ -512,14 +512,14 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Get id of object
*
- * @param Object $obj Model to create
+ * @param object $obj Model to create
* @param \ReflectionClass $refClass Reflection class
*
* @return mixed
*
* @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);
$refProp = $refClass->getProperty(static::$columns[static::$primaryField]['internal']);
@@ -541,14 +541,14 @@ class DataMapperAbstract implements DataMapperInterface
* Set id to model
*
* @param \ReflectionClass $refClass Reflection class
- * @param Object $obj Object to create
+ * @param object $obj Object to create
* @param mixed $objId Id to set
*
* @return void
*
* @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']);
@@ -568,7 +568,7 @@ class DataMapperAbstract implements DataMapperInterface
* Create has many
*
* @param \ReflectionClass $refClass Reflection class
- * @param Object $obj Object to create
+ * @param object $obj Object to create
* @param mixed $objId Id to set
*
* @return void
@@ -577,7 +577,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
$property = $refClass->getProperty($propertyName);
@@ -602,7 +602,7 @@ class DataMapperAbstract implements DataMapperInterface
$relReflectionClass = null;
foreach ($values as $key => &$value) {
- if (!is_object($value)) {
+ if (!\is_object($value)) {
// Is scalar => already in database
$objsIds[$key] = $value;
@@ -672,7 +672,7 @@ class DataMapperAbstract implements DataMapperInterface
$objsIds = [];
foreach ($values as $key => &$value) {
- if (!is_object($value)) {
+ if (!\is_array($value)) {
// Is scalar => already in database
$objsIds[$key] = $value;
@@ -706,14 +706,14 @@ class DataMapperAbstract implements DataMapperInterface
* Create has one
*
* @param \ReflectionClass $refClass Property name to initialize
- * @param Object $obj Object to create
+ * @param object $obj Object to create
*
* @return mixed
* @todo implement???
*
* @since 1.0.0
*/
- private static function createHasOne(\ReflectionClass $refClass, $obj)
+ private static function createHasOne(\ReflectionClass $refClass, object $obj)
{
throw new \Exception();
}
@@ -724,7 +724,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model
*
* @param string $propertyName Property name to initialize
- * @param Object $obj Object to create
+ * @param mixed $obj Object to create
*
* @return mixed
*
@@ -732,7 +732,7 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function createOwnsOne(string $propertyName, $obj)
{
- if (is_object($obj)) {
+ if (\is_object($obj)) {
$mapper = static::$ownsOne[$propertyName]['mapper'];
$primaryKey = $mapper::getObjectId($obj);
@@ -760,7 +760,7 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function createOwnsOneArray(string $propertyName, array &$obj)
{
- if (is_array($obj)) {
+ if (\is_array($obj)) {
$mapper = static::$ownsOne[$propertyName]['mapper'];
$primaryKey = $obj[static::$columns[static::$primaryField]['internal']];
@@ -780,7 +780,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model
*
* @param string $propertyName Property name to initialize
- * @param Object $obj Object to create
+ * @param mixed $obj Object to create
*
* @return mixed
*
@@ -788,7 +788,7 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function createBelongsTo(string $propertyName, $obj)
{
- if (is_object($obj)) {
+ if (\is_object($obj)) {
/** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper'];
$primaryKey = $mapper::getObjectId($obj);
@@ -817,7 +817,7 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function createBelongsToArray(string $propertyName, array $obj)
{
- if (is_array($obj)) {
+ if (\is_array($obj)) {
/** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper'];
$primaryKey = $obj[static::$columns[static::$primaryField]['internal']];
@@ -890,12 +890,12 @@ class DataMapperAbstract implements DataMapperInterface
} elseif ($type === 'DateTime') {
return $value->format('Y-m-d H:i:s');
} elseif ($type === 'Json' || $type === 'jsonSerializable') {
- return \json_encode($value);
+ return (string) \json_encode($value);
} elseif ($type === 'Serializable') {
return $value->serialize();
} elseif ($value instanceof \JsonSerializable) {
- return \json_encode($value->jsonSerialize());
- } elseif (is_object($value) && \method_exists($value, 'getId')) {
+ return (string) \json_encode($value->jsonSerialize());
+ } elseif (\is_object($value) && method_exists($value, 'getId')) {
return $value->getId();
}
@@ -905,9 +905,11 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Update has many
*
- * @param \ReflectionClass $refClass Reflection class
- * @param Object $obj Object to create
- * @param mixed $objId Id to set
+ * @param \ReflectionClass $refClass Reflection class
+ * @param object $obj Object to create
+ * @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
*
@@ -915,7 +917,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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 = [];
@@ -942,7 +944,7 @@ class DataMapperAbstract implements DataMapperInterface
$objsIds[$propertyName] = [];
foreach ($values as $key => &$value) {
- if (!is_object($value)) {
+ if (!\is_object($value)) {
// Is scalar => already in database
$objsIds[$propertyName][$key] = $value;
@@ -957,7 +959,7 @@ class DataMapperAbstract implements DataMapperInterface
// already in db
if (!empty($primaryKey)) {
- $mapper::update($value);
+ $mapper::update($value, $relations, $depth);
$objsIds[$propertyName][$key] = $value;
@@ -1055,24 +1057,22 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model
*
* @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
*
* @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 */
- $mapper = static::$ownsOne[$propertyName]['mapper'];
+ /** @var string $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 $obj;
+ return $mapper::update($obj, $relations, $depth);
}
/**
@@ -1081,19 +1081,21 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model
*
* @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
*
* @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 */
$mapper = static::$belongsTo[$propertyName]['mapper'];
- return $mapper::update($obj);
+ return $mapper::update($obj, $relations, $depth);
}
return $obj;
@@ -1102,15 +1104,17 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Update object in db.
*
- * @param Object $obj Model to update
- * @param mixed $objId Model id
- * @param \ReflectionClass $refClass Reflection class
+ * @param object $obj Model to update
+ * @param mixed $objId Model id
+ * @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
*
* @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->prefix(self::$db->getPrefix())
@@ -1118,7 +1122,7 @@ class DataMapperAbstract implements DataMapperInterface
->where(static::$table . '.' . static::$primaryField, '=', $objId);
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])
|| $column['internal'] === static::$primaryField
@@ -1126,6 +1130,7 @@ class DataMapperAbstract implements DataMapperInterface
continue;
}
+ $refClass = $refClass ?? new \ReflectionClass($obj);
$property = $refClass->getProperty($propertyName);
if (!($isPublic = $property->isPublic())) {
@@ -1133,24 +1138,24 @@ class DataMapperAbstract implements DataMapperInterface
}
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);
// 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']);
} 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);
// 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']);
} elseif ($column['name'] !== static::$primaryField) {
$tValue = $property->getValue($obj);
- if (stripos($column['internal'], '/') !== false) {
+ if (\stripos($column['internal'], '/') !== false) {
$path = \explode('/', $column['internal']);
- array_shift($path);
- $path = implode('/', $path);
+ \array_shift($path);
+ $path = \implode('/', $path);
$tValue = ArrayUtils::getArray($path, $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 int $relations Create all relations as well
+ * @param int $depth Depth of relations to update (default = 1 = none)
*
* @return mixed
*
* @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__);
@@ -1188,8 +1194,11 @@ class DataMapperAbstract implements DataMapperInterface
$objId = self::getObjectId($obj, $refClass);
$update = true;
- // todo: maybe don't remove obj and just update cache... ? since it might have to be loaded again
- self::removeInitialized(static::class, $objId);
+ if ($depth < 1) {
+ return $objId;
+ }
+
+ self::addInitialized(static::class, $objId, $obj);
if (empty($objId)) {
$update = false;
@@ -1197,11 +1206,11 @@ class DataMapperAbstract implements DataMapperInterface
}
if ($relations === RelationType::ALL) {
- self::updateHasMany($refClass, $obj, $objId);
+ self::updateHasMany($refClass, $obj, $objId, --$depth);
}
if ($update) {
- self::updateModel($obj, $objId, $refClass);
+ self::updateModel($obj, $objId, $refClass, --$depth);
}
return $objId;
@@ -1211,7 +1220,7 @@ class DataMapperAbstract implements DataMapperInterface
* Delete has many
*
* @param \ReflectionClass $refClass Reflection class
- * @param Object $obj Object to create
+ * @param object $obj Object to create
* @param mixed $objId Id to set
* @param int $relations Delete all relations as well
*
@@ -1221,7 +1230,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
$property = $refClass->getProperty($propertyName);
@@ -1246,7 +1255,7 @@ class DataMapperAbstract implements DataMapperInterface
$relReflectionClass = null;
foreach ($values as $key => &$value) {
- if (!is_object($value)) {
+ if (!\is_object($value)) {
// Is scalar => already in database
$objsIds[$key] = $value;
@@ -1284,7 +1293,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model
*
* @param string $propertyName Property name to initialize
- * @param Object $obj Object to delete
+ * @param mixed $obj Object to delete
*
* @return mixed
*
@@ -1292,7 +1301,7 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function deleteOwnsOne(string $propertyName, $obj)
{
- if (is_object($obj)) {
+ if (\is_object($obj)) {
/** @var string $mapper */
$mapper = static::$ownsOne[$propertyName]['mapper'];
@@ -1309,7 +1318,7 @@ class DataMapperAbstract implements DataMapperInterface
* The reference is stored in the main model
*
* @param string $propertyName Property name to initialize
- * @param Object $obj Object to delete
+ * @param mixed $obj Object to delete
*
* @return mixed
*
@@ -1317,7 +1326,7 @@ class DataMapperAbstract implements DataMapperInterface
*/
private static function deleteBelongsTo(string $propertyName, $obj)
{
- if (is_object($obj)) {
+ if (\is_object($obj)) {
/** @var string $mapper */
$mapper = static::$belongsTo[$propertyName]['mapper'];
@@ -1330,7 +1339,7 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Delete object in db.
*
- * @param Object $obj Model to delete
+ * @param object $obj Model to delete
* @param mixed $objId Model id
* @param int $relations Delete all relations as well
* @param \ReflectionClass $refClass Reflection class
@@ -1339,7 +1348,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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->prefix(self::$db->getPrefix())
@@ -1347,6 +1356,7 @@ class DataMapperAbstract implements DataMapperInterface
->from(static::$table)
->where(static::$table . '.' . static::$primaryField, '=', $objId);
+ $refClass = $refClass ?? new \ReflectionClass($obj);
$properties = $refClass->getProperties();
if ($relations === RelationType::ALL) {
@@ -1486,7 +1496,7 @@ class DataMapperAbstract implements DataMapperInterface
$parts = \explode('\\', $class);
$name = $parts[$c = (count($parts) - 1)];
$parts[$c] = 'Null' . $name;
- $class = implode('\\', $parts);
+ $class = \implode('\\', $parts);
}
if (!isset($obj)) {
@@ -1507,7 +1517,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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
$refClass = new \ReflectionClass($obj);
@@ -1523,7 +1533,7 @@ class DataMapperAbstract implements DataMapperInterface
}
$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) {
$refProp->setAccessible(false);
@@ -1543,7 +1553,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
if (!empty($values)) {
@@ -1568,7 +1578,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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);
@@ -1589,7 +1599,7 @@ class DataMapperAbstract implements DataMapperInterface
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);
$refProp->setValue($obj, $value);
@@ -1613,7 +1623,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
/** @var string $mapper */
@@ -1634,7 +1644,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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);
@@ -1655,7 +1665,7 @@ class DataMapperAbstract implements DataMapperInterface
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);
$refProp->setValue($obj, $value);
@@ -1679,7 +1689,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
/** @var string $mapper */
@@ -1700,7 +1710,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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);
@@ -1721,7 +1731,7 @@ class DataMapperAbstract implements DataMapperInterface
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);
$refProp->setValue($obj, $value);
@@ -1745,7 +1755,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
/** @var string $mapper */
@@ -1775,9 +1785,11 @@ class DataMapperAbstract implements DataMapperInterface
continue;
}
- $hasPath = false;
+ $hasPath = false;
+ $aValue = [];
+ $arrayPath = '';
- if (stripos(static::$columns[$column]['internal'], '/') !== false) {
+ if (\stripos(static::$columns[$column]['internal'], '/') !== false) {
$hasPath = true;
$path = \explode('/', static::$columns[$column]['internal']);
$refProp = $refClass->getProperty($path[0]);
@@ -1786,9 +1798,9 @@ class DataMapperAbstract implements DataMapperInterface
$refProp->setAccessible(true);
}
- array_shift($path);
- $path = implode('/', $path);
- $aValue = $refProp->getValue($obj);
+ \array_shift($path);
+ $arrayPath = \implode('/', $path);
+ $aValue = $refProp->getValue($obj);
} else {
$refProp = $refClass->getProperty(static::$columns[$column]['internal']);
@@ -1804,20 +1816,20 @@ class DataMapperAbstract implements DataMapperInterface
}
if ($hasPath) {
- $value = ArrayUtils::setArray($path, $aValue, $value, '/', true);
+ $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true);
}
$refProp->setValue($obj, $value);
} elseif (static::$columns[$column]['type'] === 'DateTime') {
$value = new \DateTime($value ?? '');
if ($hasPath) {
- $value = ArrayUtils::setArray($path, $aValue, $value, '/', true);
+ $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true);
}
$refProp->setValue($obj, $value);
} elseif (static::$columns[$column]['type'] === 'Json') {
if ($hasPath) {
- $value = ArrayUtils::setArray($path, $aValue, $value, '/', true);
+ $value = ArrayUtils::setArray($arrayPath, $aValue, $value, '/', true);
}
$refProp->setValue($obj, \json_decode($value, true));
@@ -1851,11 +1863,11 @@ class DataMapperAbstract implements DataMapperInterface
foreach ($result as $column => $value) {
if (isset(static::$columns[$column]['internal'])) {
$path = static::$columns[$column]['internal'];
- if (stripos($path, '/') !== false) {
+ if (\stripos($path, '/') !== false) {
$path = \explode('/', $path);
- array_shift($path);
- $path = implode('/', $path);
+ \array_shift($path);
+ $path = \implode('/', $path);
}
if (\in_array(static::$columns[$column]['type'], ['string', 'int', 'float', 'bool'])) {
@@ -1887,9 +1899,9 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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;
}
@@ -1925,7 +1937,7 @@ class DataMapperAbstract implements DataMapperInterface
self::addInitialized(static::class, $value, $obj[$value]);
}
- self::fillRelations($obj, $relations, isset($depth) ? --$depth : null);
+ self::fillRelations($obj, $relations, --$depth);
self::clear();
$countResulsts = count($obj);
@@ -1953,7 +1965,7 @@ class DataMapperAbstract implements DataMapperInterface
$parts = \explode('\\', $class);
$name = $parts[$c = (count($parts) - 1)];
$parts[$c] = 'Null' . $name;
- $class = implode('\\', $parts);
+ $class = \implode('\\', $parts);
return new $class();
}
@@ -1969,9 +1981,9 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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;
}
@@ -1995,7 +2007,7 @@ class DataMapperAbstract implements DataMapperInterface
self::addInitialized(static::class, $value, $obj[$value]);
}
- self::fillRelationsArray($obj, $relations, isset($depth) ? --$depth : null);
+ self::fillRelationsArray($obj, $relations, --$depth);
self::clear();
return count($obj) === 1 ? reset($obj) : $obj;
@@ -2014,9 +2026,9 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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;
}
@@ -2038,7 +2050,7 @@ class DataMapperAbstract implements DataMapperInterface
$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);
@@ -2101,10 +2113,10 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
- return null;
+ if ($depth < 1) {
+ return [];
}
if (!isset(self::$parentMapper)) {
@@ -2112,7 +2124,7 @@ class DataMapperAbstract implements DataMapperInterface
}
$obj = self::populateIterable(self::getAllRaw($lang));
- self::fillRelations($obj, $relations, isset($depth) ? --$depth : null);
+ self::fillRelations($obj, $relations, --$depth);
self::clear();
return $obj;
@@ -2129,10 +2141,10 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
- return null;
+ if ($depth < 1) {
+ return [];
}
if (!isset(self::$parentMapper)) {
@@ -2140,7 +2152,7 @@ class DataMapperAbstract implements DataMapperInterface
}
$obj = self::populateIterableArray(self::getAllRaw($lang));
- self::fillRelationsArray($obj, $relations, isset($depth) ? --$depth : null);
+ self::fillRelationsArray($obj, $relations, --$depth);
self::clear();
return $obj;
@@ -2160,7 +2172,13 @@ class DataMapperAbstract implements DataMapperInterface
$sth = self::$db->con->prepare($query->toSql());
$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 string $lang Language
*
- * @return mixed
+ * @return array
*
* @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) {
- return null;
+ if ($depth < 1) {
+ return [];
}
self::extend(__CLASS__);
@@ -2204,13 +2222,12 @@ class DataMapperAbstract implements DataMapperInterface
$sth->execute();
$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();
return $obj;
-
}
/**
@@ -2224,20 +2241,20 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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) {
- return null;
+ if ($depth < 1) {
+ return [];
}
$sth = self::$db->con->prepare($query->toSql());
$sth->execute();
$results = $sth->fetchAll(\PDO::FETCH_ASSOC);
- $results = is_bool($results) ? [] : $results;
+ $results = $results === false ? [] : $results;
$obj = self::populateIterable($results);
- self::fillRelations($obj, $relations, isset($depth) ? --$depth : null);
+ self::fillRelations($obj, $relations, --$depth);
self::clear();
return $obj;
@@ -2254,9 +2271,9 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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;
}
@@ -2275,7 +2292,7 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Fill object with relations
*
- * @param mixed $obj Objects to fill
+ * @param array $obj Objects to fill
* @param int $relations Relations type
* @param int $depth Relation depth
*
@@ -2283,9 +2300,9 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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;
}
@@ -2325,7 +2342,7 @@ class DataMapperAbstract implements DataMapperInterface
/**
* Fill object with relations
*
- * @param mixed $obj Objects to fill
+ * @param array $obj Objects to fill
* @param int $relations Relations type
* @param int $depth Relation depth
*
@@ -2333,9 +2350,9 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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;
}
@@ -2377,7 +2394,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @param mixed $primaryKey Key
*
- * @return mixed
+ * @return array
*
* @since 1.0.0
*/
@@ -2391,7 +2408,7 @@ class DataMapperAbstract implements DataMapperInterface
$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->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->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);
- return is_bool($results) ? [] : $results;
+ return $results === false ? [] : $results;
}
/**
@@ -2510,7 +2533,7 @@ class DataMapperAbstract implements DataMapperInterface
->leftOuterJoin($value['table'])
->on(new And('1', new And(new Or('d1', 'd2'), 'id')))
->where($value['table'] . '.' . $value['dst'], '=', 'NULL');
-
+
}*/
$sth = self::$db->con->prepare($query->toSql());
@@ -2608,7 +2631,7 @@ class DataMapperAbstract implements DataMapperInterface
*
* @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])) {
self::$initObjects[$mapper] = [];
@@ -2686,7 +2709,7 @@ class DataMapperAbstract implements DataMapperInterface
$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
*
- * @param object $obj Object to check
+ * @param mixed $obj Object to check
*
* @return bool
*
@@ -2722,6 +2745,6 @@ class DataMapperAbstract implements DataMapperInterface
*/
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;
}
}
diff --git a/DataStorage/Database/DatabaseType.php b/DataStorage/Database/DatabaseType.php
index 2999a3ace..8fa1a2491 100644
--- a/DataStorage/Database/DatabaseType.php
+++ b/DataStorage/Database/DatabaseType.php
@@ -30,7 +30,7 @@ abstract class DatabaseType extends Enum
{
public const MYSQL = 'mysql'; /* MySQL */
public const SQLITE = 'sqlite'; /* SQLITE */
- public const PGSQL = 2; /* PostgreSQL */
+ public const PGSQL = 'postgresql'; /* PostgreSQL */
public const ORACLE = 3; /* Oracle */
public const SQLSRV = 'mssql'; /* Microsoft SQL Server */
}
diff --git a/DataStorage/Database/GrammarAbstract.php b/DataStorage/Database/GrammarAbstract.php
index ecd7c91c0..7b85dfcd9 100644
--- a/DataStorage/Database/GrammarAbstract.php
+++ b/DataStorage/Database/GrammarAbstract.php
@@ -95,7 +95,7 @@ abstract class GrammarAbstract
{
return trim(
implode(' ',
- array_filter(
+ \array_filter(
$this->compileComponents($query),
function ($value) {
return (string) $value !== '';
@@ -169,13 +169,13 @@ abstract class GrammarAbstract
$expression = '';
foreach ($elements as $key => $element) {
- if (is_string($element) && $element !== '*') {
- if (strpos($element, '.') === false) {
+ if (\is_string($element) && $element !== '*') {
+ if (\strpos($element, '.') === false) {
$prefix = '';
}
$expression .= $this->compileSystem($element, $prefix) . ', ';
- } elseif (is_string($element) && $element === '*') {
+ } elseif (\is_string($element) && $element === '*') {
$expression .= '*, ';
} elseif ($element instanceof \Closure) {
$expression .= $element() . ', ';
@@ -204,9 +204,9 @@ abstract class GrammarAbstract
$expression = '';
foreach ($elements as $key => $element) {
- if (is_string($element) && $element !== '*') {
+ if (\is_string($element) && $element !== '*') {
$expression .= $this->compileSystem($element, $prefix) . ', ';
- } elseif (is_string($element) && $element === '*') {
+ } elseif (\is_string($element) && $element === '*') {
$expression .= '*, ';
} elseif ($element instanceof \Closure) {
$expression .= $element() . ', ';
@@ -225,20 +225,20 @@ abstract class GrammarAbstract
*
* A system is a table, a sub query or special keyword.
*
- * @param array|string $system System
- * @param string $prefix Prefix for table
+ * @param string $system System
+ * @param string $prefix Prefix for table
*
* @return string
*
* @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?
$identifier = $this->systemIdentifier;
foreach ($this->specialKeywords as $keyword) {
- if (strrpos($system, $keyword, -strlen($system)) !== false) {
+ if (\strrpos($system, $keyword, -\strlen($system)) !== false) {
$prefix = '';
$identifier = '';
}
diff --git a/DataStorage/Database/Query/Builder.php b/DataStorage/Database/Query/Builder.php
index 404e75e57..291f91b3f 100644
--- a/DataStorage/Database/Query/Builder.php
+++ b/DataStorage/Database/Query/Builder.php
@@ -38,7 +38,7 @@ final class Builder extends BuilderAbstract
/**
* Columns.
*
- * @var array ') {
$markup = $trimmedMarkup;
- $markup = \substr($markup, 3);
+ $markup = (string) \substr($markup, 3);
$position = \strpos($markup, '.*?<\/pre>(*SKIP)(*F)|(\s{2,}|\n|\t)/', ' ', $render));
}
return $render;
diff --git a/Message/Http/Rest.php b/Message/Http/Rest.php
index 3bc67adea..6cde97c18 100644
--- a/Message/Http/Rest.php
+++ b/Message/Http/Rest.php
@@ -36,35 +36,47 @@ final class Rest
*/
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()) {
+ case RequestMethod::GET:
+ curl_setopt($curl, CURLOPT_HTTPGET, true);
+ break;
case RequestMethod::PUT:
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
+ \curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
break;
case RequestMethod::DELETE:
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
+ \curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
}
if ($request->getMethod() !== RequestMethod::GET) {
- curl_setopt($curl, CURLOPT_POST, 1);
+ \curl_setopt($curl, CURLOPT_POST, 1);
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);
- curl_setopt($curl, CURLOPT_USERPWD, 'username:password');
+ if ($request->getUri()->getUser() !== '') {
+ \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_RETURNTRANSFER, 1);
+ \curl_setopt($curl, CURLOPT_URL, $request->__toString());
+ \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;
}
}
diff --git a/Message/Mail/Mail.php b/Message/Mail/Mail.php
index c9618ba4f..513ea0bab 100644
--- a/Message/Mail/Mail.php
+++ b/Message/Mail/Mail.php
@@ -123,7 +123,7 @@ class Mail
/**
* Word wrap.
*
- * @var string
+ * @var int
* @since 1.0.0
*/
protected $wordWrap = 78;
diff --git a/Module/InfoManager.php b/Module/InfoManager.php
index 1518f2cb2..197f0c479 100644
--- a/Module/InfoManager.php
+++ b/Module/InfoManager.php
@@ -85,7 +85,9 @@ final class InfoManager
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;
}
/**
diff --git a/Module/InstallerAbstract.php b/Module/InstallerAbstract.php
index 4a347780e..b7a8a2418 100644
--- a/Module/InstallerAbstract.php
+++ b/Module/InstallerAbstract.php
@@ -18,6 +18,7 @@ use phpOMS\DataStorage\Database\DatabaseType;
use phpOMS\DataStorage\Database\Exception\InvalidDatabaseTypeException;
use phpOMS\DataStorage\Database\DatabasePool;
use phpOMS\System\File\Local\Directory;
+use phpOMS\System\File\Local\File;
use phpOMS\System\File\PathException;
use phpOMS\System\File\PermissionException;
use phpOMS\Utils\Parser\Php\ArrayParser;
@@ -73,7 +74,6 @@ class InstallerAbstract
$sth->bindValue(':from', $val['from'], \PDO::PARAM_STR);
$sth->bindValue(':for', $val['for'], \PDO::PARAM_STR);
$sth->bindValue(':file', $val['file'], \PDO::PARAM_STR);
-
$sth->execute();
}
}
@@ -115,7 +115,7 @@ class InstallerAbstract
*/
private static function activate(DatabasePool $dbPool, InfoManager $info) : void
{
- /** @var ActivateAbstract $class */
+ /** @var StatusAbstract $class */
$class = '\Modules\\' . $info->getDirectory() . '\Admin\Status';
$class::activate($dbPool, $info);
}
@@ -150,11 +150,13 @@ class InstallerAbstract
{
$directories = new Directory(\dirname($info->getPath()) . '/Admin/Routes');
- foreach ($directories as $key => $subdir) {
- if ($subdir instanceof Directory) {
- foreach ($subdir as $key2 => $file) {
- self::installRoutes(__DIR__ . '/../../' . $subdir->getName() . '/' . basename($file->getName(), '.php') . '/Routes.php', $file->getPath());
+ foreach ($directories as $key => $child) {
+ if ($child instanceof Directory) {
+ foreach ($child as $key2 => $file) {
+ 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);
}
- if (!is_writable($destRoutePath)) {
+ if (!\is_writable($destRoutePath)) {
throw new PermissionException($destRoutePath);
}
@@ -194,7 +196,7 @@ class InstallerAbstract
/** @noinspection PhpIncludeInspection */
$moduleRoutes = include $srcRoutePath;
- $appRoutes = array_merge_recursive($appRoutes, $moduleRoutes);
+ $appRoutes = \array_merge_recursive($appRoutes, $moduleRoutes);
\file_put_contents($destRoutePath, 'getPath()) . '/Admin/Hooks');
- foreach ($directories as $key => $subdir) {
- if ($subdir instanceof Directory) {
- foreach ($subdir as $key2 => $file) {
- self::installHooks(__DIR__ . '/../../' . $subdir->getName() . '/' . basename($file->getName(), '.php') . '/Hooks.php', $file->getPath());
+ foreach ($directories as $key => $child) {
+ if ($child instanceof Directory) {
+ foreach ($child as $key2 => $file) {
+ 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);
}
- if (!is_writable($destHookPath)) {
+ if (!\is_writable($destHookPath)) {
throw new PermissionException($destHookPath);
}
@@ -258,7 +262,7 @@ class InstallerAbstract
/** @noinspection PhpIncludeInspection */
$moduleHooks = include $srcHookPath;
- $appHooks = array_merge_recursive($appHooks, $moduleHooks);
+ $appHooks = \array_merge_recursive($appHooks, $moduleHooks);
\file_put_contents($destHookPath, 'active === null || !$useCache) {
+ if (empty($this->active) || !$useCache) {
switch ($this->app->dbPool->get('select')->getType()) {
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->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;
default:
throw new InvalidDatabaseTypeException($this->app->dbPool->get('select')->getType());
}
}
+
+
return $this->active;
}
@@ -221,7 +236,7 @@ final class ModuleManager
*/
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
{
- if ($this->all === null) {
+ if (empty($this->all)) {
chdir($this->modulePath);
$files = glob('*', GLOB_ONLYDIR);
$c = count($files);
@@ -246,8 +261,9 @@ final class ModuleManager
// throw new PathException($path);
}
- $json = \json_decode(file_get_contents($path), true);
- $this->all[$json['name']['internal']] = $json;
+ $content = \file_get_contents($path);
+ $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
{
- if ($this->installed === null || !$useCache) {
+ if (empty($this->installed) || !$useCache) {
switch ($this->app->dbPool->get('select')->getType()) {
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();
- $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;
default:
throw new InvalidDatabaseTypeException($this->app->dbPool->get('select')->getType());
@@ -303,7 +333,7 @@ final class ModuleManager
*/
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) {
throw new PathException($oldPath);
diff --git a/Module/PackageManager.php b/Module/PackageManager.php
index b336ec7b6..d88d32bdb 100644
--- a/Module/PackageManager.php
+++ b/Module/PackageManager.php
@@ -109,7 +109,9 @@ final class PackageManager
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
{
- 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;
}
- \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);
}
/**
diff --git a/README.md b/README.md
index 3c5784431..336b975ff 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://codeclimate.com/github/Orange-Management/phpOMS/maintainability)
+[](https://travis-ci.org/Orange-Management/phpOMS)
# General
diff --git a/Router/Router.php b/Router/Router.php
index 5e58ec9bb..cac6691fd 100644
--- a/Router/Router.php
+++ b/Router/Router.php
@@ -35,15 +35,6 @@ final class Router
*/
private $routes = [];
- /**
- * Constructor.
- *
- * @since 1.0.0
- */
- public function __construct()
- {
- }
-
/**
* Add routes from file.
*
@@ -55,7 +46,7 @@ final class Router
*/
public function importFromFile(string $path) : bool
{
- if (file_exists($path)) {
+ if (\file_exists($path)) {
/** @noinspection PhpIncludeInspection */
$this->routes += include $path;
@@ -69,7 +60,7 @@ final class Router
* Add route.
*
* @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
*
* @return void
@@ -100,22 +91,22 @@ final class Router
*
* @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 = [];
foreach ($this->routes as $route => $destination) {
foreach ($destination as $d) {
- if ($this->match($route, $d['verb'], $uri, $verb)) {
- $bound[] = ['dest' => $d['dest']];
+ if ($this->match($route, $d['verb'], $request, $verb)) {
+ 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));
+ }
}
}
}
diff --git a/Security/PhpCode.php b/Security/PhpCode.php
index 716246bd9..a6ca86393 100644
--- a/Security/PhpCode.php
+++ b/Security/PhpCode.php
@@ -104,7 +104,12 @@ final class PhpCode
*/
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 = \explode(',', $disabled);
@@ -149,6 +154,21 @@ final class PhpCode
*/
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;
}
}
diff --git a/Stdlib/Base/EnumArray.php b/Stdlib/Base/EnumArray.php
index 30f7c04af..d33a314fe 100644
--- a/Stdlib/Base/EnumArray.php
+++ b/Stdlib/Base/EnumArray.php
@@ -26,6 +26,13 @@ namespace phpOMS\Stdlib\Base;
*/
abstract class EnumArray
{
+ /**
+ * Constants.
+ *
+ * @var array
+ * @since 1.0.0
+ */
+ protected static $constants = [];
/**
* Checking enum name.
diff --git a/Stdlib/Base/Iban.php b/Stdlib/Base/Iban.php
index 44d68beb5..6fea5acdf 100644
--- a/Stdlib/Base/Iban.php
+++ b/Stdlib/Base/Iban.php
@@ -115,15 +115,16 @@ class Iban implements \Serializable
{
$country = $this->getCountry();
$layout = \str_replace(' ', '', IbanEnum::getByName('C_' . $country));
+ $start = \stripos($layout, $sequence);
+ $end = \strrpos($layout, $sequence);
- $start = \stripos($layout, $sequence);
- $end = strrpos($layout, $sequence);
-
- if ($start === false) {
+ if ($start === false || $end === false) {
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
{
- return substr($this->iban, 0, 2);
+ $country = \substr($this->iban, 0, 2);
+
+ return $country === false ? '?' : $country;
}
/**
diff --git a/Stdlib/Base/Location.php b/Stdlib/Base/Location.php
index f30934767..7f772c1df 100644
--- a/Stdlib/Base/Location.php
+++ b/Stdlib/Base/Location.php
@@ -297,7 +297,7 @@ class Location implements \JsonSerializable, \Serializable
*/
public function serialize() : string
{
- return \json_encode($this->jsonSerialize());
+ return (string) \json_encode($this->jsonSerialize());
}
/**
diff --git a/Stdlib/Base/SmartDateTime.php b/Stdlib/Base/SmartDateTime.php
index cf3e617b0..d0a95f317 100644
--- a/Stdlib/Base/SmartDateTime.php
+++ b/Stdlib/Base/SmartDateTime.php
@@ -97,8 +97,8 @@ class SmartDateTime extends \DateTime
$yearNew = (int) $this->format('Y') + $y + $yearChange;
$monthNew = ((int) $this->format('m') + $m) % 12;
$monthNew = $monthNew === 0 ? 12 : $monthNew < 0 ? 12 + $monthNew : $monthNew;
- $dayMonthOld = cal_days_in_month($calendar, (int) $this->format('m'), (int) $this->format('Y'));
- $dayMonthNew = cal_days_in_month($calendar, $monthNew, $yearNew);
+ $dayMonthOld = \cal_days_in_month($calendar, (int) $this->format('m'), (int) $this->format('Y'));
+ $dayMonthNew = \cal_days_in_month($calendar, $monthNew, $yearNew);
$dayOld = (int) $this->format('d');
if ($dayOld > $dayMonthNew) {
@@ -219,7 +219,13 @@ class SmartDateTime extends \DateTime
*/
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);
}
/**
diff --git a/Stdlib/Queue/PriorityQueue.php b/Stdlib/Queue/PriorityQueue.php
index 96029929f..71357896e 100644
--- a/Stdlib/Queue/PriorityQueue.php
+++ b/Stdlib/Queue/PriorityQueue.php
@@ -53,14 +53,15 @@ class PriorityQueue implements \Countable, \Serializable
/**
* Insert element into queue.
*
- * @param mixed $data Queue element
- * @param float $priority Priority of this element
+ * @param mixed $data Queue element
+ * @param string $job Job cmd
+ * @param float $priority Priority of this element
*
* @return int
*
* @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 {
$key = rand();
@@ -78,6 +79,7 @@ class PriorityQueue implements \Countable, \Serializable
$pos++;
}
+ $original = [];
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
{
- return \json_encode($this->queue);
+ return (string) \json_encode($this->queue);
}
/**
diff --git a/System/File/ContainerInterface.php b/System/File/ContainerInterface.php
index 8084f7a70..fc999e9b3 100644
--- a/System/File/ContainerInterface.php
+++ b/System/File/ContainerInterface.php
@@ -205,7 +205,7 @@ interface ContainerInterface
* @param bool $recursive Consider subdirectories
* @param array $ignore Files/paths to ignore (no regex)
*
- * @return string
+ * @return int
*
* @since 1.0.0
*/
diff --git a/System/File/FileUtils.php b/System/File/FileUtils.php
index c61690791..d7b35825d 100644
--- a/System/File/FileUtils.php
+++ b/System/File/FileUtils.php
@@ -92,7 +92,7 @@ final class FileUtils
*/
public static function absolute(string $origPath) : string
{
- if (!\file_exists($origPath)) {
+ if (!\file_exists($origPath) || \realpath($origPath) === false) {
$startsWithSlash = strpos($origPath, '/') === 0 ? '/' : '';
$path = [];
@@ -106,15 +106,34 @@ final class FileUtils
if ($part !== '..') {
$path[] = $part;
} elseif (!empty($path)) {
- array_pop($path);
+ \array_pop($path);
} else {
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()));
+ }
}
}
diff --git a/System/File/Ftp/Directory.php b/System/File/Ftp/Directory.php
index 5a31e69a6..e12b9c441 100644
--- a/System/File/Ftp/Directory.php
+++ b/System/File/Ftp/Directory.php
@@ -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}
*/
diff --git a/System/File/Ftp/File.php b/System/File/Ftp/File.php
index 6ff95bc18..07bc15335 100644
--- a/System/File/Ftp/File.php
+++ b/System/File/Ftp/File.php
@@ -138,6 +138,14 @@ class File extends FileAbstract implements FileInterface
return $content;
}
+ /**
+ * {@inheritdoc}
+ */
+ public static function count(string $path, bool $recursive = true, array $ignore = []) : int
+ {
+
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/System/File/Local/Directory.php b/System/File/Local/Directory.php
index d5e51fe64..f07bcd5e3 100644
--- a/System/File/Local/Directory.php
+++ b/System/File/Local/Directory.php
@@ -71,7 +71,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
* @param string $path Path
* @param string $filter Filter
*
- * @return string[]
+ * @return array
*
* @since 1.0.0
*/
@@ -105,7 +105,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
* @param string $extension Extension
* @param string $exclude Pattern to exclude
*
- * @return string[]
+ * @return array
*
* @since 1.0.0
*/
@@ -168,6 +168,10 @@ final class Directory extends FileAbstract implements DirectoryInterface
$countSize = 0;
$directories = \scandir($dir);
+ if ($directories === false) {
+ return $countSize;
+ }
+
foreach ($directories as $key => $filename) {
if ($filename === ".." || $filename === ".") {
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[] = '..';
+ if ($files === false) {
+ return $size;
+ }
+
foreach ($files as $t) {
if (\in_array($t, $ignore)) {
continue;
@@ -221,6 +229,10 @@ final class Directory extends FileAbstract implements DirectoryInterface
{
$files = \scandir($path);
+ if ($files === false) {
+ return false;
+ }
+
/* Removing . and .. */
unset($files[1]);
unset($files[0]);
@@ -260,7 +272,9 @@ final class Directory extends FileAbstract implements DirectoryInterface
}
$created = new \DateTime('now');
- $created->setTimestamp(\filemtime($path));
+ $time = \filemtime($path);
+
+ $created->setTimestamp($time === false ? 0 : $time);
return $created;
}
@@ -275,7 +289,9 @@ final class Directory extends FileAbstract implements DirectoryInterface
}
$changed = new \DateTime();
- $changed->setTimestamp(\filectime($path));
+ $time = \filectime($path);
+
+ $changed->setTimestamp($time === false ? 0 : $time);
return $changed;
}
@@ -289,7 +305,7 @@ final class Directory extends FileAbstract implements DirectoryInterface
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);
}
- return \fileperms($path);
+ return (int) \fileperms($path);
}
/**
diff --git a/System/File/Local/File.php b/System/File/Local/File.php
index 2e0c84033..2f52e98f7 100644
--- a/System/File/Local/File.php
+++ b/System/File/Local/File.php
@@ -56,7 +56,7 @@ final class File extends FileAbstract implements FileInterface
{
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);
}
- 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);
}
- 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);
}
- 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);
}
- return filesize($path);
+ return (int) \filesize($path);
}
/**
@@ -219,7 +225,7 @@ final class File extends FileAbstract implements FileInterface
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);
}
- 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
{
- 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
{
- 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
{
- if (!is_file($from)) {
+ if (!\is_file($from)) {
throw new PathException($from);
}
@@ -325,7 +331,7 @@ final class File extends FileAbstract implements FileInterface
*/
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
{
- return \file_get_contents($this->path);
+ $contents = \file_get_contents($this->path);
+
+ return $contents === false ? '' : $contents;
}
/**
diff --git a/System/File/Local/FileAbstract.php b/System/File/Local/FileAbstract.php
index 2176205ea..1e4bbf37c 100644
--- a/System/File/Local/FileAbstract.php
+++ b/System/File/Local/FileAbstract.php
@@ -185,9 +185,15 @@ abstract class FileAbstract implements ContainerInterface
*/
public function index() : void
{
- $this->createdAt->setTimestamp(filemtime($this->path));
- $this->changedAt->setTimestamp(filectime($this->path));
- $this->owner = fileowner($this->path);
- $this->permission = (int) substr(sprintf('%o', fileperms($this->path)), -4);
+ $mtime = \filemtime($this->path);
+ $ctime = \filectime($this->path);
+
+ $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);
}
}
diff --git a/System/File/Local/LocalStorage.php b/System/File/Local/LocalStorage.php
index fc3860de9..f4e7420bf 100644
--- a/System/File/Local/LocalStorage.php
+++ b/System/File/Local/LocalStorage.php
@@ -54,13 +54,7 @@ class LocalStorage extends 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
+ * {@inheritdoc}
*/
protected static function getClassType(string $path) : string
{
diff --git a/System/File/StorageAbstract.php b/System/File/StorageAbstract.php
index d36e09831..48b1d8d37 100644
--- a/System/File/StorageAbstract.php
+++ b/System/File/StorageAbstract.php
@@ -43,6 +43,17 @@ abstract class 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.
*
@@ -265,7 +276,7 @@ abstract class StorageAbstract
* @param bool $recursive Consider subdirectories
* @param array $ignore Files/paths to ignore (no regex)
*
- * @return string
+ * @return int
*
* @since 1.0.0
*/
diff --git a/System/SystemUtils.php b/System/SystemUtils.php
index ce40b5a34..729e9a1d3 100644
--- a/System/SystemUtils.php
+++ b/System/SystemUtils.php
@@ -46,25 +46,27 @@ final class SystemUtils
{
$mem = 0;
- if (stristr(PHP_OS, 'WIN')) {
- $mem = null;
- exec('wmic memorychip get capacity', $mem);
+ if (\stristr(PHP_OS, 'WIN')) {
+ $memArr = [];
+ exec('wmic memorychip get capacity', $memArr);
- /** @var array $mem */
- $mem = array_sum($mem) / 1024;
- } elseif (stristr(PHP_OS, 'LINUX')) {
- $fh = fopen('/proc/meminfo', 'r');
- $mem = 0;
+ $mem = \array_sum($memArr) / 1024;
+ } elseif (\stristr(PHP_OS, 'LINUX')) {
+ $fh = \fopen('/proc/meminfo', 'r');
- while ($line = fgets($fh)) {
+ if ($fh === false) {
+ return $mem;
+ }
+
+ while ($line = \fgets($fh)) {
$pieces = [];
if (\preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces)) {
- $mem = $pieces[1] * 1024;
+ $mem = (int) ($pieces[1] ?? 0) * 1024;
break;
}
}
- fclose($fh);
+ \fclose($fh);
}
return (int) $mem;
@@ -81,12 +83,17 @@ final class SystemUtils
{
$memUsage = 0;
- if (stristr(PHP_OS, 'LINUX')) {
- $free = shell_exec('free');
- $free = (string) trim($free);
+ if (\stristr(PHP_OS, 'LINUX')) {
+ $free = \shell_exec('free');
+
+ if ($free === null) {
+ return $memUsage;
+ }
+
+ $free = trim($free);
$freeArr = \explode("\n", $free);
- $mem = \explode(" ", $freeArr[1]);
- $mem = array_values(array_filter($mem));
+ $mem = \explode(' ', $freeArr[1]);
+ $mem = \array_values(\array_filter($mem));
$memUsage = $mem[2] / $mem[1] * 100;
}
@@ -104,11 +111,11 @@ final class SystemUtils
{
$cpuUsage = 0;
- if (stristr(PHP_OS, 'WIN') !== false) {
+ if (\stristr(PHP_OS, 'WIN') !== false) {
$cpuUsage = null;
exec('wmic cpu get LoadPercentage', $cpuUsage);
$cpuUsage = $cpuUsage[1];
- } elseif (stristr(PHP_OS, 'LINUX') !== false) {
+ } elseif (\stristr(PHP_OS, 'LINUX') !== false) {
$cpuUsage = \sys_getloadavg()[0] * 100;
}
diff --git a/UnhandledHandler.php b/UnhandledHandler.php
index defda347f..2a920073b 100644
--- a/UnhandledHandler.php
+++ b/UnhandledHandler.php
@@ -61,14 +61,14 @@ final class UnhandledHandler
{
$logger = FileLogger::getInstance(__DIR__ . '/../Logs');
- if (!(error_reporting() & $errno)) {
+ if (!(\error_reporting() & $errno)) {
$logger->error(FileLogger::MSG_FULL, [
'message' => 'Undefined error',
'line' => $errline,
'file' => $errfile,
]);
- error_clear_last();
+ \error_clear_last();
return false;
}
@@ -80,7 +80,7 @@ final class UnhandledHandler
'file' => $errfile,
]);
- error_clear_last();
+ \error_clear_last();
return true;
}
@@ -95,9 +95,9 @@ final class UnhandledHandler
*/
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->warning(FileLogger::MSG_FULL, [
'message' => $e['message'],
diff --git a/Uri/Argument.php b/Uri/Argument.php
new file mode 100644
index 000000000..1b5196197
--- /dev/null
+++ b/Uri/Argument.php
@@ -0,0 +1,326 @@
+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 '';
+ }
+}
diff --git a/Uri/Http.php b/Uri/Http.php
index 647cbeb15..b9803d16f 100644
--- a/Uri/Http.php
+++ b/Uri/Http.php
@@ -145,7 +145,7 @@ final class Http implements UriInterface
public function set(string $uri) : void
{
$this->uri = $uri;
- $url = parse_url($this->uri);
+ $url = \parse_url($this->uri);
$this->scheme = $url['scheme'] ?? '';
$this->host = $url['host'] ?? '';
@@ -155,17 +155,23 @@ final class Http implements UriInterface
$this->path = $url['path'] ?? '';
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'] ?? '';
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->base = $this->scheme . '://' . $this->host . $this->rootPath;
@@ -189,7 +195,7 @@ final class Http implements UriInterface
*/
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
{
- 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
{
if ($key !== null) {
- $key = strtolower($key);
+ $key = \strtolower($key);
return $this->query[$key] ?? '';
}
@@ -289,7 +295,7 @@ final class Http implements UriInterface
*/
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
{
- return explode('/', $this->path);
+ return \explode('/', $this->path);
}
/**
diff --git a/Uri/UriFactory.php b/Uri/UriFactory.php
index 6ce3a6b12..0afe90c10 100644
--- a/Uri/UriFactory.php
+++ b/Uri/UriFactory.php
@@ -187,11 +187,10 @@ final class UriFactory
*/
private static function unique(string $url) : string
{
- $parts = \explode('?', $url);
+ $parts = \explode('&', \str_replace('?', '&', $url));
if (count($parts) >= 2) {
- $full = $parts[1];
- $pars = \explode('&', $full);
+ $pars = \array_slice($parts, 1);
$comps = [];
$length = count($pars);
diff --git a/Utils/ArrayUtils.php b/Utils/ArrayUtils.php
index 02733d7e6..839bb9eae 100644
--- a/Utils/ArrayUtils.php
+++ b/Utils/ArrayUtils.php
@@ -51,8 +51,11 @@ final class ArrayUtils
$nodes = \explode($delim, trim($path, $delim));
$prevEl = null;
$el = &$data;
+ $node = null;
- $node = null;
+ if ($nodes === false) {
+ throw new \Exception();
+ }
foreach ($nodes as &$node) {
$prevEl = &$el;
@@ -89,6 +92,10 @@ final class ArrayUtils
$pathParts = \explode($delim, trim($path, $delim));
$current = &$data;
+ if ($pathParts === false) {
+ throw new \Exception();
+ }
+
foreach ($pathParts as $key) {
$current = &$current[$key];
}
@@ -124,6 +131,10 @@ final class ArrayUtils
$pathParts = \explode($delim, trim($path, $delim));
$current = $data;
+ if ($pathParts === false) {
+ throw new \Exception();
+ }
+
foreach ($pathParts as $key) {
if (!isset($current[$key])) {
return null;
@@ -266,14 +277,19 @@ final class ArrayUtils
*/
public static function arrayToCsv(array $data, string $delimiter = ';', string $enclosure = '"', string $escape = '\\') : string
{
- $outstream = fopen('php://memory', 'r+');
- /** @noinspection PhpMethodParametersCountMismatchInspection */
- fputcsv($outstream, $data, $delimiter, $enclosure, $escape);
- rewind($outstream);
- $csv = fgets($outstream);
- fclose($outstream);
+ $outstream = \fopen('php://memory', 'r+');
- 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
{
- 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 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
{
- if (($key = array_search($id, $args)) === false) {
+ if (($key = \array_search($id, $args)) === false) {
return null;
}
- return $key;
+ return (int) $key;
}
/**
diff --git a/Utils/Barcode/C128Abstract.php b/Utils/Barcode/C128Abstract.php
index 9c730fd8d..e66572cea 100644
--- a/Utils/Barcode/C128Abstract.php
+++ b/Utils/Barcode/C128Abstract.php
@@ -147,11 +147,11 @@ abstract class C128Abstract
public function setDimension(int $width, int $height) : void
{
if ($width < 0) {
- throw new \OutOfBoundsException($width);
+ throw new \OutOfBoundsException((string) $width);
}
if ($height < 0) {
- throw new \OutOfBoundsException($height);
+ throw new \OutOfBoundsException((string) $height);
}
$this->dimension['width'] = $width;
@@ -243,8 +243,8 @@ abstract class C128Abstract
{
$res = $this->get();
- imagepng($res, $file);
- imagedestroy($res);
+ \imagepng($res, $file);
+ \imagedestroy($res);
}
/**
@@ -260,8 +260,8 @@ abstract class C128Abstract
{
$res = $this->get();
- imagejpeg($res, $file);
- imagedestroy($res);
+ \imagejpeg($res, $file);
+ \imagedestroy($res);
}
/**
@@ -273,14 +273,14 @@ abstract class C128Abstract
*/
protected function generateCodeString() : string
{
- $keys = array_keys(static::$CODEARRAY);
- $values = array_flip($keys);
+ $keys = \array_keys(static::$CODEARRAY);
+ $values = \array_flip($keys);
$codeString = '';
- $length = strlen($this->content);
+ $length = \strlen($this->content);
$checksum = static::$CHECKSUM;
for ($pos = 1; $pos <= $length; $pos++) {
- $activeKey = substr($this->content, ($pos - 1), 1);
+ $activeKey = \substr($this->content, ($pos - 1), 1);
$codeString .= static::$CODEARRAY[$activeKey];
$checksum += $values[$activeKey] * $pos;
}
@@ -302,18 +302,23 @@ abstract class C128Abstract
protected function createImage(string $codeString)
{
$dimensions = $this->calculateDimensions($codeString);
- $image = imagecreate($dimensions['width'], $dimensions['height']);
- $black = imagecolorallocate($image, 0, 0, 0);
- $white = imagecolorallocate($image, 255, 255, 255);
+ $image = \imagecreate($dimensions['width'], $dimensions['height']);
+
+ if ($image === false) {
+ throw new \Exception();
+ }
+
+ $black = \imagecolorallocate($image, 0, 0, 0);
+ $white = \imagecolorallocate($image, 255, 255, 255);
$location = 0;
- $length = strlen($codeString);
- imagefill($image, 0, 0, $white);
+ $length = \strlen($codeString);
+ \imagefill($image, 0, 0, $white);
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) {
- imagefilledrectangle(
+ \imagefilledrectangle(
$image,
$location + $this->margin,
0 + $this->margin,
@@ -322,7 +327,7 @@ abstract class C128Abstract
($position % 2 == 0 ? $white : $black)
);
} else {
- imagefilledrectangle(
+ \imagefilledrectangle(
$image,
0 + $this->margin,
$location + $this->margin,
@@ -350,10 +355,10 @@ abstract class C128Abstract
private function calculateCodeLength(string $codeString) : int
{
$codeLength = 0;
- $length = strlen($codeString);
+ $length = \strlen($codeString);
for ($i = 1; $i <= $length; ++$i) {
- $codeLength = $codeLength + (int) (substr($codeString, ($i - 1), 1));
+ $codeLength = $codeLength + (int) (\substr($codeString, ($i - 1), 1));
}
return $codeLength;
diff --git a/Utils/Compression/LZW.php b/Utils/Compression/LZW.php
index 3e8cee371..5757f9fe8 100644
--- a/Utils/Compression/LZW.php
+++ b/Utils/Compression/LZW.php
@@ -39,17 +39,17 @@ class LZW implements CompressionInterface
$dictionary[chr($i)] = $i;
}
- $length = strlen($source);
+ $length = \strlen($source);
for ($i = 0; $i < $length; ++$i) {
$c = $source[$i];
$wc = $w . $c;
- if (array_key_exists($w . $c, $dictionary)) {
+ if (\array_key_exists($w . $c, $dictionary)) {
$w = $w . $c;
} else {
$result[] = $dictionary[$w];
$dictionary[$wc] = $dictSize++;
- $w = (string) $c;
+ $w = $c;
}
}
@@ -57,7 +57,7 @@ class LZW implements CompressionInterface
$result[] = $dictionary[$w];
}
- return implode(',', $result);
+ return \implode(',', $result);
}
/**
@@ -70,16 +70,20 @@ class LZW implements CompressionInterface
$entry = '';
$dictSize = 256;
+ if (empty($compressed)) {
+ return '';
+ }
+
for ($i = 0; $i < 256; ++$i) {
$dictionary[$i] = chr($i);
}
- $w = chr($compressed[0]);
- $result = $dictionary[$compressed[0]];
+ $w = chr((int) $compressed[0]);
+ $result = $dictionary[(int) ($compressed[0])] ?? 0;
$count = count($compressed);
for ($i = 1; $i < $count; ++$i) {
- $k = $compressed[$i];
+ $k = (int) $compressed[$i];
if ($dictionary[$k]) {
$entry = $dictionary[$k];
diff --git a/Utils/Converter/Ip.php b/Utils/Converter/Ip.php
index a2e686b8b..21a86dad0 100644
--- a/Utils/Converter/Ip.php
+++ b/Utils/Converter/Ip.php
@@ -49,6 +49,9 @@ class 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);
}
}
diff --git a/Utils/Converter/Numeric.php b/Utils/Converter/Numeric.php
index eb359d177..f0d929b5a 100644
--- a/Utils/Converter/Numeric.php
+++ b/Utils/Converter/Numeric.php
@@ -64,22 +64,26 @@ class Numeric
return $numberInput;
}
- $fromBase = str_split($fromBaseInput, 1);
- $toBase = str_split($toBaseInput, 1);
- $number = str_split($numberInput, 1);
- $fromLen = strlen($fromBaseInput);
- $toLen = strlen($toBaseInput);
- $numberLen = strlen($numberInput);
+ $fromBase = \str_split($fromBaseInput, 1);
+ $toBase = \str_split($toBaseInput, 1);
+ $number = \str_split($numberInput, 1);
+ $fromLen = \strlen($fromBaseInput);
+ $toLen = \strlen($toBaseInput);
+ $numberLen = \strlen($numberInput);
$newOutput = '';
+ if ($fromBase === false || $toBase === false || $number === false) {
+ throw new \Exception();
+ }
+
if ($toBaseInput === '0123456789') {
- $newOutput = 0;
+ $newOutput = '0';
for ($i = 1; $i <= $numberLen; ++$i) {
$newOutput = bcadd(
- (string) $newOutput,
+ $newOutput,
bcmul(
- (string) array_search($number[$i - 1], $fromBase),
+ (string) \array_search($number[$i - 1], $fromBase),
bcpow((string) $fromLen, (string) ($numberLen - $i))
)
);
@@ -88,15 +92,15 @@ class Numeric
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];
}
while ($base10 !== '0') {
- $newOutput = $toBase[bcmod($base10, (string) $toLen)] . $newOutput;
- $base10 = bcdiv($base10, (string) $toLen, 0);
+ $newOutput = $toBase[(int) bcmod((string) $base10, (string) $toLen)] . $newOutput;
+ $base10 = bcdiv((string) $base10, (string) $toLen, 0);
}
return $newOutput;
@@ -144,9 +148,13 @@ class Numeric
$result = 0;
foreach (self::ROMANS as $key => $value) {
- while (strpos($roman, $key) === 0) {
+ while (\strpos($roman, $key) === 0) {
$result += $value;
- $roman = substr($roman, strlen($key));
+ $temp = \substr($roman, \strlen($key));
+
+ if ($temp !== false) {
+ $roman = $temp;
+ }
}
}
@@ -169,7 +177,7 @@ class Numeric
$alpha = '';
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);
}
@@ -188,12 +196,12 @@ class Numeric
public static function alphaToNumeric(string $alpha) : int
{
$numeric = 0;
- $length = strlen($alpha);
+ $length = \strlen($alpha);
for ($i = 0; $i < $length; ++$i) {
$numeric += pow(26, $i) * (ord($alpha[$length - $i - 1]) - 0x40);
}
- return $numeric - 1;
+ return (int) $numeric - 1;
}
}
diff --git a/Utils/Encoding/Huffman/Huffman.php b/Utils/Encoding/Huffman/Huffman.php
index b79f5d7d3..165a1c73e 100644
--- a/Utils/Encoding/Huffman/Huffman.php
+++ b/Utils/Encoding/Huffman/Huffman.php
@@ -82,11 +82,15 @@ final class Huffman
$binary .= $this->dictionary->get($source[$i]);
}
- $splittedBinaryString = str_split('1' . $binary . '1', 8);
+ $splittedBinaryString = \str_split('1' . $binary . '1', 8);
$binary = '';
+ if ($splittedBinaryString === false) {
+ return $binary;
+ }
+
foreach ($splittedBinaryString as $i => $c) {
- while (strlen($c) < 8) {
+ while (\strlen($c) < 8) {
$c .= '0';
}
@@ -112,22 +116,40 @@ final class Huffman
}
$binary = '';
- $rawLenght = strlen($raw);
+ $rawLenght = \strlen($raw);
$source = '';
for ($i = 0; $i < $rawLenght; ++$i) {
$decbin = decbin(ord($raw[$i]));
- while (strlen($decbin) < 8) {
+ while (\strlen($decbin) < 8) {
$decbin = '0' . $decbin;
}
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) {
- $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;
diff --git a/Utils/Git/Commit.php b/Utils/Git/Commit.php
index 758468bec..e31bcaf48 100644
--- a/Utils/Git/Commit.php
+++ b/Utils/Git/Commit.php
@@ -101,7 +101,7 @@ class Commit
$this->author = new Author();
$this->branch = new Branch();
$this->tag = new Tag();
- $this->repository = new Repository(realpath(__DIR__ . '/../../../../../'));
+ $this->repository = new Repository();
}
/**
diff --git a/Utils/Git/Git.php b/Utils/Git/Git.php
index 2c6c5ef6c..ffd3c6e5e 100644
--- a/Utils/Git/Git.php
+++ b/Utils/Git/Git.php
@@ -45,16 +45,16 @@ class Git
public static function test() : bool
{
$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]);
- $stderr = stream_get_contents($pipes[2]);
+ $stdout = \stream_get_contents($pipes[1]);
+ $stderr = \stream_get_contents($pipes[2]);
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
{
- if (realpath($path) === false) {
+ if (\realpath($path) === false) {
throw new PathException($path);
}
- self::$bin = realpath($path);
+ self::$bin = \realpath($path);
}
}
diff --git a/Utils/Git/Repository.php b/Utils/Git/Repository.php
index 3e9c69d11..fd84f731c 100644
--- a/Utils/Git/Repository.php
+++ b/Utils/Git/Repository.php
@@ -67,9 +67,11 @@ class Repository
*
* @since 1.0.0
*/
- public function __construct(string $path)
+ public function __construct(string $path = '')
{
- $this->setPath($path);
+ if (\is_dir($path)) {
+ $this->setPath($path);
+ }
}
/**
@@ -85,20 +87,16 @@ class Repository
*/
private function setPath(string $path) : void
{
- if (!is_dir($path)) {
+ if (!\is_dir($path) || \realpath($path) === false) {
throw new PathException($path);
}
- $this->path = realpath($path);
+ $this->path = \realpath($path);
- if ($this->path === false) {
- throw new PathException($path);
- }
-
- if (file_exists($this->path . '/.git') && \is_dir($this->path . '/.git')) {
+ if (\file_exists($this->path . '/.git') && \is_dir($this->path . '/.git')) {
$this->bare = false;
- } elseif (is_file($this->path . '/config')) { // Is this a bare repo?
- $parseIni = parse_ini_file($this->path . '/config');
+ } elseif (\is_file($this->path . '/config')) { // Is this a bare repo?
+ $parseIni = \parse_ini_file($this->path . '/config');
if ($parseIni['bare']) {
$this->bare = true;
@@ -128,7 +126,7 @@ class Repository
public function getActiveBranch() : Branch
{
$branches = $this->getBranches();
- $active = preg_grep('/^\*/', $branches);
+ $active = \preg_grep('/^\*/', $branches);
reset($active);
return new Branch(current($active));
@@ -170,14 +168,14 @@ class Repository
*/
private function run(string $cmd) : array
{
- if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
- $cmd = 'cd ' . escapeshellarg(\dirname(Git::getBin()))
- . ' && ' . basename(Git::getBin())
- . ' -C ' . escapeshellarg($this->path) . ' '
+ if (\strtolower((string) \substr(PHP_OS, 0, 3)) == 'win') {
+ $cmd = 'cd ' . \escapeshellarg(\dirname(Git::getBin()))
+ . ' && ' . \basename(Git::getBin())
+ . ' -C ' . \escapeshellarg($this->path) . ' '
. $cmd;
} else {
- $cmd = escapeshellarg(Git::getBin())
- . ' -C ' . escapeshellarg($this->path) . ' '
+ $cmd = \escapeshellarg(Git::getBin())
+ . ' -C ' . \escapeshellarg($this->path) . ' '
. $cmd;
}
@@ -187,15 +185,20 @@ class Repository
2 => ['pipe', 'w'],
];
- $resource = proc_open($cmd, $desc, $pipes, $this->path, null);
- $stdout = stream_get_contents($pipes[1]);
- $stderr = stream_get_contents($pipes[2]);
+ $resource = \proc_open($cmd, $desc, $pipes, $this->path, null);
- foreach ($pipes as $pipe) {
- fclose($pipe);
+ if ($resource === false) {
+ throw new \Exception();
}
- $status = trim(proc_close($resource));
+ $stdout = \stream_get_contents($pipes[1]);
+ $stderr = \stream_get_contents($pipes[2]);
+
+ foreach ($pipes as $pipe) {
+ \fclose($pipe);
+ }
+
+ $status = \proc_close($resource);
if ($status == -1) {
throw new \Exception($stderr);
@@ -215,11 +218,15 @@ class Repository
*/
private function parseLines(string $lines) : array
{
- $lineArray = preg_split('/\r\n|\n|\r/', $lines);
+ $lineArray = \preg_split('/\r\n|\n|\r/', $lines);
$lines = [];
+ if ($lineArray === false) {
+ return $lines;
+ }
+
foreach ($lineArray as $key => $line) {
- $temp = preg_replace('/\s+/', ' ', trim($line, ' '));
+ $temp = \preg_replace('/\s+/', ' ', trim($line, ' '));
if (!empty($temp)) {
$lines[] = $temp;
@@ -242,7 +249,7 @@ class Repository
*/
public function create(string $source = null) : void
{
- if (!is_dir($this->path) || \file_exists($this->path . '/.git')) {
+ if (!\is_dir($this->path) || \file_exists($this->path . '/.git')) {
throw new \Exception('Already repository');
}
@@ -264,7 +271,7 @@ class Repository
*/
public function status() : string
{
- return implode("\n", $this->run('status'));
+ return \implode("\n", $this->run('status'));
}
/**
@@ -282,7 +289,7 @@ class Repository
{
$files = $this->parseFileList($files);
- return implode("\n", $this->run('add ' . $files . ' -v'));
+ return \implode("\n", $this->run('add ' . $files . ' -v'));
}
/**
@@ -299,7 +306,7 @@ class Repository
{
$files = $this->parseFileList($files);
- return implode("\n", $this->run('rm ' . ($cached ? '--cached ' : '') . $files));
+ return \implode("\n", $this->run('rm ' . ($cached ? '--cached ' : '') . $files));
}
/**
@@ -315,9 +322,9 @@ class Repository
*/
private function parseFileList($files) : string
{
- if (is_array($files)) {
- return '"' . implode('" "', $files) . '"';
- } elseif (!is_string($files)) {
+ if (\is_array($files)) {
+ return '"' . \implode('" "', $files) . '"';
+ } elseif (!\is_string($files)) {
throw new \InvalidArgumentException('Wrong type for $files.');
}
@@ -336,7 +343,7 @@ class Repository
*/
public function commit(Commit $commit, $all = true) : string
{
- return implode("\n", $this->run('commit ' . ($all ? '-av' : '-v') . ' -m ' . escapeshellarg($commit->getMessage())));
+ return \implode("\n", $this->run('commit ' . ($all ? '-av' : '-v') . ' -m ' . \escapeshellarg($commit->getMessage())));
}
/**
@@ -352,11 +359,11 @@ class Repository
*/
public function cloneTo(string $target) : string
{
- if (!is_dir($target)) {
+ if (!\is_dir($target)) {
throw new PathException($target);
}
- return implode("\n", $this->run('clone --local ' . $this->path . ' ' . $target));
+ return \implode("\n", $this->run('clone --local ' . $this->path . ' ' . $target));
}
/**
@@ -372,11 +379,11 @@ class Repository
*/
public function cloneFrom(string $source) : string
{
- if (!is_dir($source)) {
+ if (!\is_dir($source)) {
throw new PathException($source);
}
- return implode("\n", $this->run('clone --local ' . $source . ' ' . $this->path));
+ return \implode("\n", $this->run('clone --local ' . $source . ' ' . $this->path));
}
/**
@@ -390,7 +397,7 @@ class Repository
*/
public function cloneRemote(string $source) : string
{
- return implode("\n", $this->run('clone ' . $source . ' ' . $this->path));
+ return \implode("\n", $this->run('clone ' . $source . ' ' . $this->path));
}
/**
@@ -405,7 +412,7 @@ class Repository
*/
public function clean(bool $dirs = false, bool $force = false) : string
{
- return implode("\n", $this->run('clean' . ($force ? ' -f' : '') . ($dirs ? ' -d' : '')));
+ return \implode("\n", $this->run('clean' . ($force ? ' -f' : '') . ($dirs ? ' -d' : '')));
}
/**
@@ -420,7 +427,7 @@ class Repository
*/
public function createBranch(Branch $branch, bool $force = false) : string
{
- return implode("\n", $this->run('branch ' . ($force ? '-D' : '-d') . ' ' . $branch->getName()));
+ return \implode("\n", $this->run('branch ' . ($force ? '-D' : '-d') . ' ' . $branch->getName()));
}
/**
@@ -488,7 +495,7 @@ class Repository
*/
public function checkout(Branch $branch) : string
{
- $result = implode("\n", $this->run('checkout ' . $branch->getName()));
+ $result = \implode("\n", $this->run('checkout ' . $branch->getName()));
$this->branch = $branch;
return $result;
@@ -505,7 +512,7 @@ class Repository
*/
public function merge(Branch $branch) : string
{
- return implode("\n", $this->run('merge ' . $branch->getName() . ' --no-ff'));
+ return \implode("\n", $this->run('merge ' . $branch->getName() . ' --no-ff'));
}
/**
@@ -517,7 +524,7 @@ class Repository
*/
public function fetch() : string
{
- return implode("\n", $this->run('fetch'));
+ return \implode("\n", $this->run('fetch'));
}
/**
@@ -531,7 +538,7 @@ class Repository
*/
public function createTag(Tag $tag) : string
{
- return implode("\n", $this->run('tag -a ' . $tag->getName() . ' -m ' . escapeshellarg($tag->getMessage())));
+ return \implode("\n", $this->run('tag -a ' . $tag->getName() . ' -m ' . \escapeshellarg($tag->getMessage())));
}
/**
@@ -568,9 +575,9 @@ class Repository
*/
public function push(string $remote, Branch $branch) : string
{
- $remote = escapeshellarg($remote);
+ $remote = \escapeshellarg($remote);
- return implode("\n", $this->run('push --tags ' . $remote . ' ' . $branch->getName()));
+ return \implode("\n", $this->run('push --tags ' . $remote . ' ' . $branch->getName()));
}
/**
@@ -587,7 +594,7 @@ class Repository
{
$remote = escapeshellarg($remote);
- return implode("\n", $this->run('pull ' . $remote . ' ' . $branch->getName()));
+ return \implode("\n", $this->run('pull ' . $remote . ' ' . $branch->getName()));
}
/**
@@ -613,7 +620,7 @@ class Repository
*/
public function getDescription() : string
{
- return \file_get_contents($this->getDirectoryPath() . '/description');
+ return (string) \file_get_contents($this->getDirectoryPath() . '/description');
}
/**
@@ -657,18 +664,18 @@ class Repository
return 0;
}
- $fh = fopen($path, 'r');
+ $fh = \fopen($path, 'r');
if (!$fh) {
return 0;
}
while (!feof($fh)) {
- fgets($fh);
+ \fgets($fh);
$loc++;
}
- fclose($fh);
+ \fclose($fh);
}
return $loc;
@@ -700,7 +707,8 @@ class Repository
foreach ($lines as $line) {
\preg_match('/^[0-9]*/', $line, $matches);
- $contributor = new Author(substr($line, strlen($matches[0]) + 1));
+ $author = \substr($line, \strlen($matches[0]) + 1);
+ $contributor = new Author($author === false ? '' : $author);
$contributor->setCommitCount($this->getCommitsCount($start, $end)[$contributor->getName()]);
$addremove = $this->getAdditionsRemovalsByContributor($contributor, $start, $end);
@@ -739,7 +747,7 @@ class Repository
foreach ($lines as $line) {
\preg_match('/^[0-9]*/', $line, $matches);
- $commits[substr($line, strlen($matches[0]) + 1)] = (int) $matches[0];
+ $commits[\substr($line, \strlen($matches[0]) + 1)] = (int) $matches[0];
}
return $commits;
@@ -768,7 +776,7 @@ class Repository
$addremove = ['added' => 0, 'removed' => 0];
$lines = $this->run(
- 'log --author=' . escapeshellarg($author->getName())
+ 'log --author=' . \escapeshellarg($author->getName())
. ' --since="' . $start->format('Y-m-d')
. '" --before="' . $end->format('Y-m-d')
. '" --pretty=tformat: --numstat'
@@ -793,7 +801,7 @@ class Repository
*/
public function getRemote() : string
{
- return implode("\n", $this->run('config --get remote.origin.url'));
+ return \implode("\n", $this->run('config --get remote.origin.url'));
}
/**
@@ -820,7 +828,7 @@ class Repository
if ($author === null) {
$author = '';
} else {
- $author = ' --author=' . escapeshellarg($author->getName()) . '';
+ $author = ' --author=' . \escapeshellarg($author->getName()) . '';
}
$lines = $this->run(
@@ -865,7 +873,7 @@ class Repository
\preg_match('/[0-9ABCDEFabcdef]{40}/', $lines[0], $matches);
- if (!isset($matches[0]) || strlen($matches[0]) !== 40) {
+ if (!isset($matches[0]) || \strlen($matches[0]) !== 40) {
throw new \Exception('Invalid commit id');
}
@@ -874,8 +882,16 @@ class Repository
}
$author = \explode(':', $lines[1] ?? '');
- $author = \explode('<', trim($author[1] ?? ''));
- $date = substr($lines[2] ?? '', 6);
+ if (count($author) < 2) {
+ $author = ['none', 'none'];
+ } else {
+ $author = \explode('<', trim($author[1] ?? ''));
+ }
+
+ $date = \substr($lines[2] ?? '', 6);
+ if ($date === false) {
+ $date = 'now';
+ }
$commit = new Commit($matches[0]);
$commit->setAuthor(new Author(trim($author[0] ?? ''), rtrim($author[1] ?? '', '>')));
@@ -913,7 +929,7 @@ class Repository
\preg_match('/[0-9ABCDEFabcdef]{40}/', $lines[0], $matches);
- if (!isset($matches[0]) || strlen($matches[0]) !== 40) {
+ if (!isset($matches[0]) || \strlen($matches[0]) !== 40) {
throw new \Exception('Invalid commit id');
}
diff --git a/Utils/IO/Csv/CsvDatabaseMapper.php b/Utils/IO/Csv/CsvDatabaseMapper.php
deleted file mode 100644
index 26489fe94..000000000
--- a/Utils/IO/Csv/CsvDatabaseMapper.php
+++ /dev/null
@@ -1,90 +0,0 @@
-db = $db;
- }
-
- public function addSource(string $source)
- {
- $this->sources[] = $source;
-
- $this->sources = array_unique($this->sources);
- }
-
- public function setSources(array $sources) : void
- {
- $this->sources = $sources;
- }
-
- public function autoIdentifyCsvSettings(bool $identify)
- {
- $this->autoIdentifyCsvSettings = $identify;
- }
-
- public function setLineBuffer(int $buffer) : void
- {
- $this->lineBuffer = $buffer;
- }
-
- public function insert()
- {
- foreach ($this->sources as $source) {
- $file = fopen($source, 'r');
- $header = [];
- $delimiter = $this->autoIdentifyCsvSettings ? $this->getFileDelimiter($file, 100) : $this->delimiter;
-
- if (feof($file) && ($line = fgetcsv($file, 0, $delimiter)) !== false) {
- $header = $line;
- }
-
- $query = new Builder($this->db);
- $query->insert(...$header)->into(\str_replace(' ', '', explode($source, '.')));
-
- while (feof($file)) {
- $c = 0;
-
- while (($line = fgetcsv($file)) !== false && $c < $this->lineBuffer && feof($file)) {
- $query->values($line);
- $c++;
- }
-
- $this->db->con->prepare($query->toSql())->execute();
- }
-
- fclose($file);
- }
- }
-}
diff --git a/Utils/IO/Csv/CsvSettings.php b/Utils/IO/Csv/CsvSettings.php
index 0523273e4..f001235a9 100644
--- a/Utils/IO/Csv/CsvSettings.php
+++ b/Utils/IO/Csv/CsvSettings.php
@@ -25,9 +25,9 @@ class CsvSettings
/**
* Get csv file delimiter.
*
- * @param mixed $file File resource
- * @param int $checkLines Lines to check for evaluation
- * @param array $delimiters Potential delimiters
+ * @param mixed $file File resource
+ * @param int $checkLines Lines to check for evaluation
+ * @param string[] $delimiters Potential delimiters
*
* @return string
*
@@ -36,14 +36,23 @@ class CsvSettings
public static function getFileDelimiter($file, int $checkLines = 2, array $delimiters = [',', '\t', ';', '|', ':']) : string
{
$results = [];
+ $i = 0;
+ $line = \fgets($file);
- $i = 0;
- while (($line = fgets($file)) !== false && $i < $checkLines) {
+ if ($line === false) {
+ return ';';
+ }
+
+ while ($line !== false && $i < $checkLines) {
$i++;
foreach ($delimiters as $delimiter) {
$regExp = '/[' . $delimiter . ']/';
- $fields = preg_split($regExp, $line);
+ $fields = \preg_split($regExp, $line);
+
+ if ($fields === false) {
+ return ';';
+ }
if (count($fields) > 1) {
if (!empty($results[$delimiter])) {
@@ -55,7 +64,7 @@ class CsvSettings
}
}
- $results = array_keys($results, max($results));
+ $results = \array_keys($results, max($results));
return $results[0];
}
diff --git a/Utils/IO/Zip/Gz.php b/Utils/IO/Zip/Gz.php
index 47e3ea97f..922a2ea6e 100644
--- a/Utils/IO/Zip/Gz.php
+++ b/Utils/IO/Zip/Gz.php
@@ -31,23 +31,25 @@ class Gz implements ArchiveInterface
*/
public static function pack($source, string $destination, bool $overwrite = true) : bool
{
- $destination = \str_replace('\\', '/', realpath($destination));
+ $destination = \str_replace('\\', '/', $destination);
if (!$overwrite && \file_exists($destination)) {
return false;
}
- if (($gz = gzopen($destination, 'w')) === false) {
+ $gz = \gzopen($destination, 'w');
+ $src = \fopen($source, 'r');
+ if ($gz === false || $src === false) {
return false;
}
- $src = fopen($source, 'r');
- while (!feof($src)) {
- gzwrite($gz, fread($src, 4096));
+ while (!\feof($src)) {
+ $read = \fread($src, 4096);
+ \gzwrite($gz, $read === false ? '' : $read);
}
- fclose($src);
+ \fclose($src);
- return gzclose($gz);
+ return \gzclose($gz);
}
/**
@@ -55,22 +57,23 @@ class Gz implements ArchiveInterface
*/
public static function unpack(string $source, string $destination) : bool
{
- $destination = \str_replace('\\', '/', realpath($destination));
- if (file_exists($destination)) {
+ $destination = \str_replace('\\', '/', $destination);
+ if (\file_exists($destination)) {
return false;
}
- if (($gz = gzopen($source, 'w')) === false) {
+ $gz = \gzopen($source, 'w');
+ $dest = \fopen($destination, 'w');
+ if ($gz === false || $dest === false) {
return false;
}
- $dest = fopen($destination, 'w');
- while (!gzeof($gz)) {
- fwrite($dest, gzread($gz, 4096));
+ while (!\gzeof($gz)) {
+ \fwrite($dest, \gzread($gz, 4096));
}
- fclose($dest);
+ \fclose($dest);
- return gzclose($gz);
+ return \gzclose($gz);
}
}
diff --git a/Utils/IO/Zip/Tar.php b/Utils/IO/Zip/Tar.php
index 498494215..71695911e 100644
--- a/Utils/IO/Zip/Tar.php
+++ b/Utils/IO/Zip/Tar.php
@@ -14,6 +14,8 @@ declare(strict_types=1);
namespace phpOMS\Utils\IO\Zip;
+use phpOMS\System\File\FileUtils;
+
/**
* Zip class for handling zip files.
*
@@ -31,48 +33,57 @@ class Tar implements ArchiveInterface
*/
public static function pack($sources, string $destination, bool $overwrite = true) : bool
{
- $destination = \str_replace('\\', '/', realpath($destination));
+ $destination = FileUtils::absolute(\str_replace('\\', '/', $destination));
if (!$overwrite && \file_exists($destination)) {
return false;
}
+ $tar = new \PharData($destination);
+
/** @var array $sources */
- foreach ($sources as $source) {
- $source = \str_replace('\\', '/', realpath($source));
+ foreach ($sources as $source => $relative) {
+ $source = \realpath($source);
+
+ if ($source === false) {
+ continue;
+ }
+
+ $source = \str_replace('\\', '/', $source);
if (!\file_exists($source)) {
continue;
}
- if (is_dir($source)) {
- $files = new \RecursiveIteratorIterator(
- new \RecursiveDirectoryIterator($source),
- \RecursiveIteratorIterator::SELF_FIRST
- );
+ if (\is_dir($source)) {
+ $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = \str_replace('\\', '/', $file);
/* Ignore . and .. */
- if (\in_array(mb_substr($file, mb_strrpos($file, '/') + 1), ['.', '..'])) {
+ if (($pos = \mb_strrpos($file, '/')) === false
+ || \in_array(\mb_substr($file, $pos + 1), ['.', '..'])
+ ) {
continue;
}
- $file = realpath($file);
+ $absolute = \realpath($file);
+ $absolute = \str_replace('\\', '/', (string) $absolute);
+ $dir = \str_replace($source . '/', '', $relative . '/' . $absolute);
- if (is_dir($file)) {
- // todo: do work here
- } elseif (is_file($file)) {
- // todo: do work here
+ if (\is_dir($absolute)) {
+ $tar->addEmptyDir($dir . '/');
+ } elseif (\is_file($absolute)) {
+ $tar->addFile($absolute, $dir);
}
}
- } elseif (is_file($source)) {
- // todo: do work here
+ } elseif (\is_file($source)) {
+ $tar->addFile($source, $relative);
}
}
- fwrite($tar, pack('a1024', ''));
+ return true;
}
/**
@@ -80,6 +91,16 @@ class Tar implements ArchiveInterface
*/
public static function unpack(string $source, string $destination) : bool
{
+ if (!\file_exists($source)) {
+ return false;
+ }
+ $destination = \str_replace('\\', '/', $destination);
+ $destination = \rtrim($destination, '/');
+ $tar = new \PharData($destination);
+
+ $tar->extractTo($destination . '/');
+
+ return true;
}
}
diff --git a/Utils/IO/Zip/Zip.php b/Utils/IO/Zip/Zip.php
index 0060cc868..a330e48cb 100644
--- a/Utils/IO/Zip/Zip.php
+++ b/Utils/IO/Zip/Zip.php
@@ -47,34 +47,42 @@ class Zip implements ArchiveInterface
/** @var array $sources */
foreach ($sources as $source => $relative) {
- $source = \str_replace('\\', '/', realpath($source));
+ $source = \realpath($source);
+
+ if ($source === false) {
+ continue;
+ }
+
+ $source = \str_replace('\\', '/', $source);
if (!\file_exists($source)) {
continue;
}
- if (is_dir($source)) {
+ if (\is_dir($source)) {
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = \str_replace('\\', '/', $file);
/* Ignore . and .. */
- if (\in_array(mb_substr($file, mb_strrpos($file, '/') + 1), ['.', '..'])) {
+ if (($pos = \mb_strrpos($file, '/')) === false
+ || \in_array(\mb_substr($file, $pos + 1), ['.', '..'])
+ ) {
continue;
}
- $absolute = realpath($file);
- $absolute = \str_replace('\\', '/', $absolute);
+ $absolute = \realpath($file);
+ $absolute = \str_replace('\\', '/', (string) $absolute);
$dir = \str_replace($source . '/', '', $relative . '/' . $absolute);
- if (is_dir($absolute)) {
+ if (\is_dir($absolute)) {
$zip->addEmptyDir($dir . '/');
- } elseif (is_file($absolute)) {
+ } elseif (\is_file($absolute)) {
$zip->addFile($absolute, $dir);
}
}
- } elseif (is_file($source)) {
+ } elseif (\is_file($source)) {
$zip->addFile($source, $relative);
}
}
@@ -92,7 +100,7 @@ class Zip implements ArchiveInterface
}
$destination = \str_replace('\\', '/', $destination);
- $destination = rtrim($destination, '/');
+ $destination = \rtrim($destination, '/');
$zip = new \ZipArchive();
if (!$zip->open($source)) {
diff --git a/Utils/ImageUtils.php b/Utils/ImageUtils.php
index 9cd030d7b..914a61690 100644
--- a/Utils/ImageUtils.php
+++ b/Utils/ImageUtils.php
@@ -51,6 +51,6 @@ final class ImageUtils
$img = \str_replace('data:image/png;base64,', '', $img);
$img = \str_replace(' ', '+', $img);
- return base64_decode($img);
+ return (string) base64_decode($img);
}
}
diff --git a/Utils/JsonBuilder.php b/Utils/JsonBuilder.php
index f96d709bf..08a92fa21 100644
--- a/Utils/JsonBuilder.php
+++ b/Utils/JsonBuilder.php
@@ -80,7 +80,7 @@ final class JsonBuilder implements \Serializable, \JsonSerializable
*/
public function serialize() : string
{
- return \json_encode($this->json);
+ return (string) \json_encode($this->json);
}
/**
diff --git a/Utils/Parser/Markdown/Markdown.php b/Utils/Parser/Markdown/Markdown.php
index e50abfbd6..f81edd4de 100644
--- a/Utils/Parser/Markdown/Markdown.php
+++ b/Utils/Parser/Markdown/Markdown.php
@@ -15,6 +15,8 @@ declare(strict_types=1);
namespace phpOMS\Utils\Parser\Markdown;
+use phpOMS\Uri\UriFactory;
+
/**
* Markdown parser class.
*
@@ -769,7 +771,7 @@ class Markdown
}
$data = [
- 'url' => $matches[2],
+ 'url' => UriFactory::build($matches[2]),
'title' => $matches[3] ?? null,
];
@@ -978,17 +980,17 @@ class Markdown
$inline['position'] = $markerPosition;
}
- $unmarkedText = \substr($text, 0, $inline['position']);
+ $unmarkedText = (string) \substr($text, 0, $inline['position']);
$markup .= self::unmarkedText($unmarkedText);
$markup .= isset($inline['markup']) ? $inline['markup'] : self::element($inline['element']);
- $text = \substr($text, $inline['position'] + $inline['extent']);
+ $text = (string) \substr($text, $inline['position'] + $inline['extent']);
continue 2;
}
- $unmarkedText = \substr($text, 0, $markerPosition + 1);
+ $unmarkedText = (string) \substr($text, 0, $markerPosition + 1);
$markup .= self::unmarkedText($unmarkedText);
- $text = \substr($text, $markerPosition + 1);
+ $text = (string) \substr($text, $markerPosition + 1);
}
$markup .= self::unmarkedText($text);
@@ -1049,7 +1051,7 @@ class Markdown
'name' => 'a',
'text' => $matches[1],
'attributes' => [
- 'href' => $url,
+ 'href' => UriFactory::build($url),
],
],
];
@@ -1140,7 +1142,7 @@ class Markdown
'element' => [
'name' => 'img',
'attributes' => [
- 'src' => $link['element']['attributes']['href'],
+ 'src' => UriFactory::build($link['element']['attributes']['href']),
'alt' => $link['element']['text'],
],
],
@@ -1183,13 +1185,13 @@ class Markdown
$element['text'] = $matches[1];
$extent += \strlen($matches[0]);
- $remainder = \substr($remainder, $extent);
+ $remainder = (string) \substr($remainder, $extent);
if (\preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) {
- $element['attributes']['href'] = $matches[1];
+ $element['attributes']['href'] = UriFactory::build($matches[1]);
if (isset($matches[2])) {
- $element['attributes']['title'] = \substr($matches[2], 1, - 1);
+ $element['attributes']['title'] = (string) \substr($matches[2], 1, - 1);
}
$extent += \strlen($matches[0]);
@@ -1209,7 +1211,7 @@ class Markdown
$def = self::$definitionData['Reference'][$definition];
- $element['attributes']['href'] = $def['url'];
+ $element['attributes']['href'] = UriFactory::build($def['url']);
$element['attributes']['title'] = $def['title'];
}
@@ -1302,7 +1304,7 @@ class Markdown
'name' => 'a',
'text' => $matches[0][0],
'attributes' => [
- 'href' => $matches[0][0],
+ 'href' => UriFactory::build($matches[0][0]),
],
],
];
@@ -1329,7 +1331,7 @@ class Markdown
'name' => 'a',
'text' => $matches[1],
'attributes' => [
- 'href' => $matches[1],
+ 'href' => UriFactory::build($matches[1]),
],
],
];
@@ -1363,7 +1365,7 @@ class Markdown
*/
protected static function element(array $element) : string
{
- $element = self::sanitizeElement($element);
+ $element = self::sanitizeAndBuildElement($element);
$markup = '<' . $element['name'];
if (isset($element['attributes'])) {
@@ -1425,7 +1427,7 @@ class Markdown
if (!\in_array('', $lines) && \substr($trimmedMarkup, 0, 3) === '
'; @@ -184,7 +184,7 @@ class Text } /** @noinspection PhpUndefinedVariableInspection */ - if ($this->hasFormatting && array_key_exists($i, $formatting)) { + if ($this->hasFormatting && isset($formatting[$i])) { $word = '<' . $formatting[$i] . '>' . $word . '' . $formatting[$i] . '>'; } @@ -276,11 +276,11 @@ class Text * * @param int $length Amount of sentences * - * @return string + * @return array * * @since 1.0.0 */ - private function generateParagraph(int $length) : string + private function generateParagraph(int $length) : array { $minSentence = 3; $maxSentence = 10; diff --git a/Utils/StringCompare.php b/Utils/StringCompare.php index abbc4345f..6009214f4 100644 --- a/Utils/StringCompare.php +++ b/Utils/StringCompare.php @@ -98,15 +98,19 @@ final class StringCompare */ public static function valueWords(string $s1, string $s2) : int { - $words1 = preg_split('/[ _-]/', $s1); - $words2 = preg_split('/[ _-]/', $s2); + $words1 = \preg_split('/[ _-]/', $s1); + $words2 = \preg_split('/[ _-]/', $s2); $total = 0; + if ($words1 === false || $words2 === false) { + return PHP_INT_MAX; + } + foreach ($words1 as $word1) { - $best = strlen($s2); + $best = \strlen($s2); foreach ($words2 as $word2) { - $wordDist = levenshtein($word1, $word2); + $wordDist = \levenshtein($word1, $word2); if ($wordDist < $best) { $best = $wordDist; @@ -136,7 +140,7 @@ final class StringCompare */ public static function valuePhrase(string $s1, string $s2) : int { - return levenshtein($s1, $s2); + return \levenshtein($s1, $s2); } /** @@ -151,7 +155,7 @@ final class StringCompare */ public static function valueLength(string $s1, string $s2) : int { - return (int) abs(strlen($s1) - strlen($s2)); + return abs(\strlen($s1) - \strlen($s2)); } /** diff --git a/Utils/StringUtils.php b/Utils/StringUtils.php index 50c46f306..3ef63e202 100644 --- a/Utils/StringUtils.php +++ b/Utils/StringUtils.php @@ -50,8 +50,6 @@ final class StringUtils * @param array $needles Needles to check if any of them are part of the haystack * * @example StringUtils::contains('This string', ['This', 'test']); // true - * @example StringUtils::contains('This string', 'is st'); // true - * @example StringUtils::contains('This string', 'something'); // false * * @return bool The function returns true if any of the needles is part of the haystack, false otherwise. * @@ -77,8 +75,6 @@ final class StringUtils * @param array $needles Needles to check if any of them are part of the haystack * * @example StringUtils::mb_contains('This string', ['This', 'test']); // true - * @example StringUtils::mb_contains('This string', 'is st'); // true - * @example StringUtils::mb_contains('This string', 'something'); // false * * @return bool The function returns true if any of the needles is part of the haystack, false otherwise. * @@ -105,8 +101,6 @@ final class StringUtils * @param string|array $needles Needles to check if they are at the end of the haystack. * * @example StringUtils::endsWith('Test string', ['test1', 'string']); // true - * @example StringUtils::endsWith('Test string', 'string'); // true - * @example StringUtils::endsWith('Test string', 'String'); // false * * @return bool The function returns true if any of the needles is at the end of the haystack, false otherwise. * diff --git a/Utils/TaskSchedule/Cron.php b/Utils/TaskSchedule/Cron.php index 37171fee6..1bc6035c5 100644 --- a/Utils/TaskSchedule/Cron.php +++ b/Utils/TaskSchedule/Cron.php @@ -25,57 +25,83 @@ namespace phpOMS\Utils\TaskSchedule; */ class Cron extends SchedulerAbstract { - /** - * Run command - * - * @param string $cmd Command to run - * - * @return string - * - * @throws \Exception - * - * @since 1.0.0 + * {@inheritdoc} */ - private function run(string $cmd) : string + public function create(TaskAbstract $task) : void { - $cmd = 'cd ' . escapeshellarg(\dirname(self::$bin)) . ' && ' . basename(self::$bin) . ' ' . $cmd; - - $pipes = []; - $desc = [ - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], - ]; - - $resource = proc_open($cmd, $desc, $pipes, __DIR__, null); - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - - foreach ($pipes as $pipe) { - fclose($pipe); - } - - $status = trim((string) proc_close($resource)); - - if ($status == -1) { - throw new \Exception($stderr); - } - - return trim($stdout); + $this->run('-l > ' . __DIR__ . '/tmpcron.tmp'); + \file_put_contents(__DIR__ . '/tmpcron.tmp', $task->__toString() . "\n", FILE_APPEND); + $this->run(__DIR__ . '/tmpcron.tmp'); + unlink(__DIR__ . '/tmpcron.tmp'); } /** - * Normalize run result for easier parsing - * - * @param string $raw Raw command output - * - * @return string Normalized string for parsing - * - * @since 1.0.0 + * {@inheritdoc} */ - private function normalize(string $raw) : string + public function update(TaskAbstract $task) : void { - return \str_replace("\r\n", "\n", $raw); + $this->run('-l > ' . __DIR__ . '/tmpcron.tmp'); + + $new = ''; + $fp = \fopen(__DIR__ . '/tmpcron.tmp', 'r+'); + + if ($fp) { + $line = \fgets($fp); + while ($line !== false) { + if ($line[0] !== '#' && \stripos($line, 'name="' . $task->getId()) !== false) { + $new .= $task->__toString() . "\n"; + } else { + $new .= $line . "\n"; + } + + $line = \fgets($fp); + } + + \fclose($fp); + \file_put_contents(__DIR__ . '/tmpcron.tmp', $new); + } + + $this->run(__DIR__ . '/tmpcron.tmp'); + unlink(__DIR__ . '/tmpcron.tmp'); + } + + /** + * {@inheritdoc} + */ + public function delete(TaskAbstract $task) : void + { + $this->deleteByName($task->getId()); + } + + /** + * {@inheritdoc} + */ + public function deleteByName(string $name) : void + { + $this->run('-l > ' . __DIR__ . '/tmpcron.tmp'); + + $new = ''; + $fp = \fopen(__DIR__ . '/tmpcron.tmp', 'r+'); + + if ($fp) { + $line = \fgets($fp); + while ($line !== false) { + if ($line[0] !== '#' && \stripos($line, 'name="' . $name) !== false) { + $line = \fgets($fp); + continue; + } + + $new .= $line . "\n"; + $line = \fgets($fp); + } + + \fclose($fp); + \file_put_contents(__DIR__ . '/tmpcron.tmp', $new); + } + + $this->run(__DIR__ . '/tmpcron.tmp'); + unlink(__DIR__ . '/tmpcron.tmp'); } /** @@ -83,16 +109,36 @@ class Cron extends SchedulerAbstract */ public function getAll() : array { - $lines = \explode("\n", $this->normalize($this->run('-l'))); - unset($lines[0]); + $this->run('-l > ' . __DIR__ . '/tmpcron.tmp'); $jobs = []; - foreach ($lines as $line) { - if ($line !== '' && strrpos($line, '#', -strlen($line)) === false) { - $jobs[] = CronJob::createWith(str_getcsv($line, ' ')); + $fp = \fopen(__DIR__ . '/tmpcron.tmp', 'r+'); + + if ($fp) { + $line = \fgets($fp); + while ($line !== false) { + if ($line[0] !== '#') { + $elements = []; + $namePos = \stripos($line, 'name="'); + $nameEndPos = \stripos($line, '"', $namePos + 7); + + if ($namePos !== false && $nameEndPos !== false) { + $elements[] = \substr($line, $namePos + 6, $nameEndPos - 1); + } + + $elements = \array_merge($elements, \explode(' ', $line)); + $jobs[] = CronJob::createWith($elements); + } + + $line = \fgets($fp); } + + \fclose($fp); } + $this->run(__DIR__ . '/tmpcron.tmp'); + unlink(__DIR__ . '/tmpcron.tmp'); + return $jobs; } @@ -101,29 +147,30 @@ class Cron extends SchedulerAbstract */ public function getAllByName(string $name, bool $exact = true) : array { - $lines = \explode("\n", $this->normalize($this->run('-l'))); - unset($lines[0]); + $this->run('-l > ' . __DIR__ . '/tmpcron.tmp'); - if ($exact) { - $jobs = []; - foreach ($lines as $line) { - $csv = str_getcsv($line, ' '); + $jobs = []; + $fp = \fopen(__DIR__ . '/tmpcron.tmp', 'r+'); - if ($line !== '' && strrpos($line, '#', -strlen($line)) === false && $csv[5] === $name) { - $jobs[] = CronJob::createWith($csv); + if ($fp) { + $line = \fgets($fp); + while ($line !== false) { + if ($line[0] !== '#' && \stripos($line, '# name="' . $name) !== false) { + $elements = []; + $elements[] = $name; + $elements += \explode(' ', $line); + $jobs[] = CronJob::createWith($elements); } - } - } else { - $jobs = []; - foreach ($lines as $line) { - $csv = str_getcsv($line, ' '); - if ($line !== '' && strrpos($line, '#', -strlen($line)) === false && \stripos($csv[5], $name) !== false) { - $jobs[] = CronJob::createWith($csv); - } + $line = \fgets($fp); } + + \fclose($fp); } + $this->run(__DIR__ . '/tmpcron.tmp'); + unlink(__DIR__ . '/tmpcron.tmp'); + return $jobs; } } diff --git a/Utils/TaskSchedule/CronJob.php b/Utils/TaskSchedule/CronJob.php index 9df129406..be874ef24 100644 --- a/Utils/TaskSchedule/CronJob.php +++ b/Utils/TaskSchedule/CronJob.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace phpOMS\Utils\TaskSchedule; +use phpOMS\Validation\Base\DateTime; + /** * CronJob class. * @@ -24,15 +26,22 @@ namespace phpOMS\Utils\TaskSchedule; */ class CronJob extends TaskAbstract { + /** + * {@inheritdoc} + */ + public function __toString() : string + { + return $this->interval . ' ' . $this->command . ' # name="' . $this->id . '" ' . $this->comment; + } + /** * {@inheritdoc} */ public static function createWith(array $jobData) : TaskAbstract { - $job = new self($jobData[5], ''); + $interval = \array_splice($jobData, 1, 4); + $job = new self($jobData[0], $jobData[1], \implode(' ', $interval)); - $job->setRun($jobData[5]); - - return $job; + return $job; } } diff --git a/Utils/TaskSchedule/NullCronJob.php b/Utils/TaskSchedule/NullCronJob.php new file mode 100644 index 000000000..03928ac29 --- /dev/null +++ b/Utils/TaskSchedule/NullCronJob.php @@ -0,0 +1,27 @@ +id . ' ' . $this->interval . ' ' . $this->command; + } + /** * {@inheritdoc} */ public static function createWith(array $jobData) : TaskAbstract { - $job = new self($jobData[1], ''); + $job = new self($jobData[1], $jobData[8]); - $job->setRun($jobData[8]); - $job->setStatus($jobData[3]); + $job->setStatus($jobData[3]); - if (DateTime::isValid($jobData[2])) { - $job->setNextRunTime(new \DateTime($jobData[2])); - } + if (DateTime::isValid($jobData[2])) { + $job->setNextRunTime(new \DateTime($jobData[2])); + } - if (DateTime::isValid($jobData[5])) { - $job->setLastRuntime(new \DateTime($jobData[5])); - } + if (DateTime::isValid($jobData[5])) { + $job->setLastRuntime(new \DateTime($jobData[5])); + } - $job->setComment($jobData[10]); - $job->addResult($jobData[6]); + $job->setComment($jobData[10]); - return $job; + return $job; } } diff --git a/Utils/TaskSchedule/SchedulerAbstract.php b/Utils/TaskSchedule/SchedulerAbstract.php index cd7ed7436..86bd2b094 100644 --- a/Utils/TaskSchedule/SchedulerAbstract.php +++ b/Utils/TaskSchedule/SchedulerAbstract.php @@ -34,7 +34,7 @@ abstract class SchedulerAbstract * @var string * @since 1.0.0 */ - protected static $bin = ''; + private static $bin = ''; /** * Get git binary. @@ -61,11 +61,44 @@ abstract class SchedulerAbstract */ public static function setBin(string $path) : void { - if (realpath($path) === false) { + if (\realpath($path) === false) { throw new PathException($path); } - self::$bin = realpath($path); + self::$bin = \realpath($path); + } + + /** + * Gues git binary. + * + * @return bool + * + * @since 1.0.0 + */ + public static function guessBin() : bool + { + $paths = [ + 'c:/WINDOWS/system32/schtasks.exe', + 'd:/WINDOWS/system32/schtasks.exe', + 'e:/WINDOWS/system32/schtasks.exe', + 'f:/WINDOWS/system32/schtasks.exe', + '/usr/bin/crontab', + '/usr/local/bin/crontab', + '/usr/local/sbin/crontab', + '/usr/sbin/crontab', + '/bin/crontab', + '/sbin/crontab', + ]; + + foreach ($paths as $path) { + if (\file_exists($path)) { + self::setBin($path); + + return true; + } + } + + return false; } /** @@ -79,16 +112,62 @@ abstract class SchedulerAbstract public static function test() : bool { $pipes = []; - $resource = proc_open(escapeshellarg(self::$bin), [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); + $resource = \proc_open(\escapeshellarg(self::$bin), [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - - foreach ($pipes as $pipe) { - fclose($pipe); + if ($resource === false) { + return false; } - return trim(proc_close($resource)) !== 127; + $stdout = \stream_get_contents($pipes[1]); + $stderr = \stream_get_contents($pipes[2]); + + foreach ($pipes as $pipe) { + \fclose($pipe); + } + + return \proc_close($resource) !== 127; + } + + /** + * Run command + * + * @param string $cmd Command to run + * + * @return string + * + * @throws \Exception + * + * @since 1.0.0 + */ + protected function run(string $cmd) : string + { + $cmd = 'cd ' . \escapeshellarg(\dirname(self::$bin)) . ' && ' . \basename(self::$bin) . ' ' . $cmd; + + $pipes = []; + $desc = [ + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ]; + + $resource = \proc_open($cmd, $desc, $pipes, __DIR__, null); + if ($resource === false) { + return ''; + } + + $stdout = \stream_get_contents($pipes[1]); + $stderr = \stream_get_contents($pipes[2]); + + foreach ($pipes as $pipe) { + \fclose($pipe); + } + + $status = \proc_close($resource); + + if ($status === -1) { + throw new \Exception($stderr); + } + + return trim($stdout); } /** @@ -100,8 +179,64 @@ abstract class SchedulerAbstract * * @since 1.0.0 */ - public function create(TaskAbstract $task) : void + abstract public function create(TaskAbstract $task) : void; + + /** + * Update task + * + * @param TaskAbstract $task Task to update + * + * @return void + * + * @since 1.0.0 + */ + abstract public function update(TaskAbstract $task) : void; + + /** + * Delete task by name + * + * @param string $name Task name + * + * @return void + * + * @since 1.0.0 + */ + abstract public function deleteByName(string $name) : void; + + /** + * Delete task + * + * @param TaskAbstract $task Task to delete + * + * @return void + * + * @since 1.0.0 + */ + abstract public function delete(TaskAbstract $task) : void; + + /** + * Normalize run result for easier parsing + * + * @param string $raw Raw command output + * + * @return string Normalized string for parsing + * + * @since 1.0.0 + */ + protected function normalize(string $raw) : string { - $this->run($task->getCommand()); + return \str_replace("\r\n", "\n", $raw); } + + /** + * Get all jobs/tasks by name + * + * @param string $name Name of the job + * @param bool $exact Name has to be exact + * + * @return array + * + * @since 1.0.0 + */ + abstract public function getAllByName(string $name, bool $exact = true) : array; } diff --git a/Utils/TaskSchedule/TaskAbstract.php b/Utils/TaskSchedule/TaskAbstract.php index 76df199b4..ca8607a93 100644 --- a/Utils/TaskSchedule/TaskAbstract.php +++ b/Utils/TaskSchedule/TaskAbstract.php @@ -41,12 +41,12 @@ abstract class TaskAbstract protected $command = ''; /** - * Command/script to run. + * Run interval * * @var string * @since 1.0.0 */ - protected $run = ''; + protected $interval = ''; /** * Status of the task @@ -91,10 +91,11 @@ abstract class TaskAbstract * * @since 1.0.0 */ - public function __construct(string $name, string $cmd = '') + public function __construct(string $name, string $cmd = '', string $interval = '') { $this->id = $name; $this->command = $cmd; + $this->interval = $interval; $this->lastRunTime = new \DateTime('1900-01-01'); $this->nextRunTime = new \DateTime('1900-01-01'); } @@ -111,6 +112,15 @@ abstract class TaskAbstract return $this->id; } + /** + * Stringify task for direct handling + * + * @return string + * + * @since 1.0.0 + */ + abstract public function __toString() : string; + /** * Get command to create the task * @@ -138,29 +148,29 @@ abstract class TaskAbstract } /** - * Get command/script to run + * Get interval to create the task * * @return string * * @since 1.0.0 */ - public function getRun() : string + public function getInterval() : string { - return $this->run; + return $this->interval; } /** - * Set script to run + * Set interval to create the task * - * @param string $run Command/script to run + * @param string $interval Interval * * @return void * * @since 1.0.0 */ - public function setRun(string $run) : void + public function setInterval(string $interval) : void { - $this->run = $run; + $this->interval = $interval; } /** diff --git a/Utils/TaskSchedule/TaskScheduler.php b/Utils/TaskSchedule/TaskScheduler.php index 6d76c6ba3..3f88a392e 100644 --- a/Utils/TaskSchedule/TaskScheduler.php +++ b/Utils/TaskSchedule/TaskScheduler.php @@ -26,55 +26,35 @@ namespace phpOMS\Utils\TaskSchedule; class TaskScheduler extends SchedulerAbstract { /** - * Run command - * - * @param string $cmd Command to run - * - * @return string - * - * @throws \Exception - * - * @since 1.0.0 + * {@inheritdoc} */ - private function run(string $cmd) : string + public function create(TaskAbstract $task) : void { - $cmd = 'cd ' . escapeshellarg(\dirname(self::$bin)) . ' && ' . basename(self::$bin) . ' ' . $cmd; - - $pipes = []; - $desc = [ - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], - ]; - - $resource = proc_open($cmd, $desc, $pipes, __DIR__, null); - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - - foreach ($pipes as $pipe) { - fclose($pipe); - } - - $status = trim((string) proc_close($resource)); - - if ($status == -1) { - throw new \Exception($stderr); - } - - return trim($stdout); + $this->run('/Create ' . $task->__toString()); } /** - * Normalize run result for easier parsing - * - * @param string $raw Raw command output - * - * @return string Normalized string for parsing - * - * @since 1.0.0 + * {@inheritdoc} */ - private function normalize(string $raw) : string + public function update(TaskAbstract $task) : void { - return \str_replace("\r\n", "\n", $raw); + $this->run('/Change ' . $task->__toString()); + } + + /** + * {@inheritdoc} + */ + public function deleteByName(string $name) : void + { + $this->run('/Delete /TN ' . $name); + } + + /** + * {@inheritdoc} + */ + public function delete(TaskAbstract $task) : void + { + $this->deleteByName($task->getId()); } /** @@ -87,7 +67,7 @@ class TaskScheduler extends SchedulerAbstract $jobs = []; foreach ($lines as $line) { - $jobs[] = Schedule::createWith(str_getcsv($line)); + $jobs[] = Schedule::createWith(\str_getcsv($line)); } return $jobs; @@ -99,12 +79,12 @@ class TaskScheduler extends SchedulerAbstract public function getAllByName(string $name, bool $exact = true) : array { if ($exact) { - $lines = \explode("\n", $this->normalize($this->run('/query /v /fo CSV /tn ' . escapeshellarg($name)))); + $lines = \explode("\n", $this->normalize($this->run('/query /v /fo CSV /tn ' . \escapeshellarg($name)))); unset($lines[0]); $jobs = []; foreach ($lines as $line) { - $jobs[] = Schedule::createWith(str_getcsv($line)); + $jobs[] = Schedule::createWith(\str_getcsv($line)); } } else { $lines = \explode("\n", $this->normalize($this->run('/query /v /fo CSV'))); @@ -112,9 +92,9 @@ class TaskScheduler extends SchedulerAbstract $jobs = []; foreach ($lines as $key => $line) { - $line = str_getcsv($line); + $line = \str_getcsv($line); - if (stripos($line[1], $name) !== false) { + if (\stripos($line[1], $name) !== false) { $jobs[] = Schedule::createWith($line); } } diff --git a/Utils/TestUtils.php b/Utils/TestUtils.php index 6f23b4a72..52ad9ff16 100644 --- a/Utils/TestUtils.php +++ b/Utils/TestUtils.php @@ -48,9 +48,9 @@ final class TestUtils * * @since 1.0.0 */ - public static function setMember(/* object */ $obj, string $name, $value) : bool + public static function setMember($obj, string $name, $value) : bool { - $reflectionClass = new \ReflectionClass(is_string($obj) ? $obj : get_class($obj)); + $reflectionClass = new \ReflectionClass(\is_string($obj) ? $obj : \get_class($obj)); if (!$reflectionClass->hasProperty($name)) { return false; @@ -62,7 +62,11 @@ final class TestUtils $reflectionProperty->setAccessible(true); } - $reflectionProperty->setValue($obj, $value); + if (\is_string($obj)) { + $reflectionProperty->setValue($value); + } elseif (\is_object($obj)) { + $reflectionProperty->setValue($obj, $value); + } if (!$accessible) { $reflectionProperty->setAccessible(false); @@ -83,7 +87,7 @@ final class TestUtils */ public static function getMember($obj, string $name) { - $reflectionClass = new \ReflectionClass(is_string($obj) ? $obj : get_class($obj)); + $reflectionClass = new \ReflectionClass(\is_string($obj) ? $obj : \get_class($obj)); if (!$reflectionClass->hasProperty($name)) { return null; @@ -95,7 +99,12 @@ final class TestUtils $reflectionProperty->setAccessible(true); } - $value = $reflectionProperty->getValue($obj); + $value = null; + if (\is_string($obj)) { + $value = $reflectionProperty->getValue(); + } elseif (\is_object($obj)) { + $value = $reflectionProperty->getValue($obj); + } if (!$accessible) { $reflectionProperty->setAccessible(false); diff --git a/Validation/Finance/Iban.php b/Validation/Finance/Iban.php index 00884dda2..f18fc508d 100644 --- a/Validation/Finance/Iban.php +++ b/Validation/Finance/Iban.php @@ -31,8 +31,14 @@ final class Iban extends ValidatorAbstract */ public static function isValid($value, array $constraints = null) : bool { - $value = \str_replace(' ', '', strtolower($value)); - $enumName = 'C_' . strtoupper(substr($value, 0, 2)); + $value = \str_replace(' ', '', \strtolower($value)); + + $temp = \substr($value, 0, 2); + if ($temp === false) { + return false; + } + + $enumName = 'C_' . \strtoupper($temp); if (!IbanEnum::isValidName($enumName)) { self::$error = IbanErrorType::INVALID_COUNTRY; @@ -42,7 +48,7 @@ final class Iban extends ValidatorAbstract $layout = \str_replace(' ', '', IbanEnum::getByName($enumName)); - if (strlen($value) !== strlen($layout)) { + if (\strlen($value) !== \strlen($layout)) { self::$error = IbanErrorType::INVALID_LENGTH; return false; @@ -81,12 +87,12 @@ final class Iban extends ValidatorAbstract */ private static function validateZeros(string $iban, string $layout) : bool { - if (strpos($layout, '0') === false) { + if (\strpos($layout, '0') === false) { return true; } $lastPos = 0; - while (($lastPos = strpos($layout, '0', $lastPos)) !== false) { + while (($lastPos = \strpos($layout, '0', $lastPos)) !== false) { if ($iban[$lastPos] !== '0') { return false; } @@ -109,13 +115,13 @@ final class Iban extends ValidatorAbstract */ private static function validateNumeric(string $iban, string $layout) : bool { - if (strpos($layout, 'n') === false) { + if (\strpos($layout, 'n') === false) { return true; } $lastPos = 0; - while (($lastPos = strpos($layout, 'n', $lastPos)) !== false) { - if (!is_numeric($iban[$lastPos])) { + while (($lastPos = \strpos($layout, 'n', $lastPos)) !== false) { + if (!\is_numeric($iban[$lastPos])) { return false; } @@ -139,18 +145,18 @@ final class Iban extends ValidatorAbstract $chars = ['a' => 10, 'b' => 11, 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, 'g' => 16, 'h' => 17, 'i' => 18, 'j' => 19, 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23, 'o' => 24, 'p' => 25, 'q' => 26, 'r' => 27, 's' => 28, 't' => 29, 'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, 'z' => 35,]; - $moved = substr($iban, 4) . substr($iban, 0, 4); - $movedArray = str_split($moved); + $moved = \substr($iban, 4) . \substr($iban, 0, 4); + $movedArray = (array) \str_split($moved); $new = ''; foreach ($movedArray as $key => $value) { - if (!is_numeric($movedArray[$key])) { + if (!\is_numeric($movedArray[$key])) { $movedArray[$key] = $chars[$movedArray[$key]]; } $new .= $movedArray[$key]; } - return bcmod($new, '97') == 1; + return \bcmod($new, '97') == 1; } } diff --git a/Validation/Network/Email.php b/Validation/Network/Email.php index b6cfa2cb1..9cfdf0b8b 100644 --- a/Validation/Network/Email.php +++ b/Validation/Network/Email.php @@ -42,7 +42,7 @@ abstract class Email extends ValidatorAbstract */ public static function isValid($value, array $constraints = null) : bool { - if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) { + if (\filter_var($value, FILTER_VALIDATE_EMAIL) === false) { self::$msg = 'Invalid Email by filter_var standards'; self::$error = 1; diff --git a/Validation/Validator.php b/Validation/Validator.php index 090156223..9c2c917f8 100644 --- a/Validation/Validator.php +++ b/Validation/Validator.php @@ -34,6 +34,8 @@ final class Validator extends ValidatorAbstract * @param array $constraints Constraints for validation * * @return bool + * + * @throws \Exception * * @since 1.0.0 */ @@ -44,14 +46,13 @@ final class Validator extends ValidatorAbstract } foreach ($constraints as $test => $settings) { - $callback = StringUtils::endsWith($test, 'Not') ? substr($test, 0, -3) : $test; + $callback = StringUtils::endsWith($test, 'Not') ? \substr($test, 0, -3) : (string) $test; - if (!empty($settings)) { - $valid = $callback($var, ...$settings); - } else { - $valid = $callback($var); + if (!\is_callable($callback)) { + throw new \Exception(); } + $valid = !empty($settings) ? $callback($var, ...$settings) : $callback($var); $valid = (StringUtils::endsWith($test, 'Not') ? !$valid : $valid); if (!$valid) { diff --git a/Views/View.php b/Views/View.php index 57b663d57..466fcfa06 100644 --- a/Views/View.php +++ b/Views/View.php @@ -177,25 +177,33 @@ class View extends ViewAbstract if ($module === null) { $match = '/Modules/'; - if (($start = strripos($this->template, $match)) === false) { + if (($start = \strripos($this->template, $match)) === false) { throw new InvalidModuleException($module ?? ''); } - $start = $start + strlen($match); - $end = strpos($this->template, '/', $start); - $module = substr($this->template, $start, $end - $start); + $start = $start + \strlen($match); + $end = \strpos($this->template, '/', $start); + $module = \substr($this->template, $start, $end - $start); + } + + if ($module === false) { + $module = '0'; } if ($theme === null) { $match = '/Theme/'; - if (($start = strripos($this->template, $match)) === false) { + if (($start = \strripos($this->template, $match)) === false) { throw new InvalidThemeException($theme ?? ''); } - $start = $start + strlen($match); - $end = strpos($this->template, '/', $start); - $theme = substr($this->template, $start, $end - $start); + $start = $start + \strlen($match); + $end = \strpos($this->template, '/', $start); + $theme = \substr($this->template, $start, $end - $start); + } + + if ($theme === false) { + $theme = '0'; } return $this->app->l11nManager->getText($this->l11n->getLanguage(), $module, $theme, $translation); diff --git a/Views/ViewAbstract.php b/Views/ViewAbstract.php index 8861a24ab..53a817794 100644 --- a/Views/ViewAbstract.php +++ b/Views/ViewAbstract.php @@ -203,7 +203,7 @@ abstract class ViewAbstract implements \Serializable public function serialize() : string { if (empty($this->template)) { - return \json_encode($this->toArray()); + return (string) \json_encode($this->toArray()); } return $this->render(); @@ -253,10 +253,10 @@ abstract class ViewAbstract implements \Serializable ob_start(); /** @noinspection PhpIncludeInspection */ $includeData = include $path; - $ob = ob_get_clean(); + $ob = (string) ob_get_clean(); if (is_array($includeData)) { - return \json_encode($includeData); + return (string) \json_encode($includeData); } } catch (\Throwable $e) { $ob = ''; diff --git a/composer.json b/composer.json index 3190c2f28..9a403e873 100644 --- a/composer.json +++ b/composer.json @@ -7,18 +7,11 @@ "email": "spl1nes.com@googlemail.com" } ], - "require": { - "php": "^7.0" - }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/Orange-Management/phpOMS.git" - } - ], - "autoload": { - "psr-0" : { - "phpOMS" : "" - } + "require-dev": { + "phpunit/phpunit": "~6.4", + "squizlabs/php_codesniffer": "~3.2", + "phpmd/phpmd": "~2.6", + "phpstan/phpstan": "~0.10.1", + "codeclimate/php-test-reporter": "^0.4.4" } -} \ No newline at end of file +} diff --git a/tests/Asset/AssetManagerTest.php b/tests/Asset/AssetManagerTest.php index 6e379a259..30b28e96f 100644 --- a/tests/Asset/AssetManagerTest.php +++ b/tests/Asset/AssetManagerTest.php @@ -64,14 +64,12 @@ class AssetManagerTest extends \PHPUnit\Framework\TestCase self::assertEquals(2, $manager->count()); /* Test remove */ - $rem = $manager->remove('myAsset'); - self::assertTrue($rem); + self::assertTrue($manager->remove('myAsset')); self::assertEquals(1, $manager->count()); self::assertNull($manager->get('myAsset')); - $rem = $manager->remove('myAsset'); - self::assertFalse($rem); + self::assertFalse($manager->remove('myAsset')); self::assertEquals(1, $manager->count()); } diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 3b0892a21..186173f1e 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -2,14 +2,108 @@ ini_set('memory_limit', '2048M'); -require_once __DIR__ . '/../../vendor/autoload.php'; -require_once __DIR__ . '/Autoloader.php'; -$CONFIG = require_once __DIR__ . '/../../config.php'; +if (file_exists('vendor/autoload.php')) { + include_once 'vendor/autoload.php'; +} elseif (file_exists('../../vendor/autoload.php')) { + include_once '../../vendor/autoload.php'; +} + +require_once __DIR__ . '/../Autoloader.php'; use phpOMS\DataStorage\Session\HttpSession; use phpOMS\DataStorage\Database\DatabasePool; use phpOMS\DataStorage\Database\DataMapperAbstract; +$CONFIG = [ + 'db' => [ + 'core' => [ + 'masters' => [ + 'admin' => [ + 'db' => 'mysql', /* db type */ + 'host' => '127.0.0.1', /* db host address */ + 'port' => '3306', /* db host port */ + 'login' => 'root', /* db login name */ + 'password' => '', /* db login password */ + 'database' => 'oms', /* db name */ + 'prefix' => 'oms_', /* db table prefix */ + 'weight' => 1000, /* db table prefix */ + ], + 'insert' => [ + 'db' => 'mysql', /* db type */ + 'host' => '127.0.0.1', /* db host address */ + 'port' => '3306', /* db host port */ + 'login' => 'root', /* db login name */ + 'password' => '', /* db login password */ + 'database' => 'oms', /* db name */ + 'prefix' => 'oms_', /* db table prefix */ + 'weight' => 1000, /* db table prefix */ + ], + 'select' => [ + 'db' => 'mysql', /* db type */ + 'host' => '127.0.0.1', /* db host address */ + 'port' => '3306', /* db host port */ + 'login' => 'root', /* db login name */ + 'password' => '', /* db login password */ + 'database' => 'oms', /* db name */ + 'prefix' => 'oms_', /* db table prefix */ + 'weight' => 1000, /* db table prefix */ + ], + 'update' => [ + 'db' => 'mysql', /* db type */ + 'host' => '127.0.0.1', /* db host address */ + 'port' => '3306', /* db host port */ + 'login' => 'root', /* db login name */ + 'password' => '', /* db login password */ + 'database' => 'oms', /* db name */ + 'prefix' => 'oms_', /* db table prefix */ + 'weight' => 1000, /* db table prefix */ + ], + 'delete' => [ + 'db' => 'mysql', /* db type */ + 'host' => '127.0.0.1', /* db host address */ + 'port' => '3306', /* db host port */ + 'login' => 'root', /* db login name */ + 'password' => '', /* db login password */ + 'database' => 'oms', /* db name */ + 'prefix' => 'oms_', /* db table prefix */ + 'weight' => 1000, /* db table prefix */ + ], + 'schema' => [ + 'db' => 'mysql', /* db type */ + 'host' => '127.0.0.1', /* db host address */ + 'port' => '3306', /* db host port */ + 'login' => 'root', /* db login name */ + 'password' => '', /* db login password */ + 'database' => 'oms', /* db name */ + 'prefix' => 'oms_', /* db table prefix */ + 'weight' => 1000, /* db table prefix */ + ], + ], + ], + ], + 'log' => [ + 'file' => [ + 'path' => __DIR__ . '/Logs', + ], + ], + 'page' => [ + 'root' => '/', + 'https' => false, + ], + 'socket' => [ + 'master' => [ + 'host' => '127.0.0.1', + 'limit' => 300, + 'port' => 4310, + ], + ], + 'language' => [ + 'en', + ], + 'apis' => [ + ] +]; + // Reset database $db = new \PDO($CONFIG['db']['core']['masters']['admin']['db'] . ':host=' . $CONFIG['db']['core']['masters']['admin']['host'], diff --git a/tests/Console/CommandManagerTest.php b/tests/Console/CommandManagerTest.php deleted file mode 100644 index 60e60ba76..000000000 --- a/tests/Console/CommandManagerTest.php +++ /dev/null @@ -1,26 +0,0 @@ -get('key')); - self::assertGreaterThan(0, strlen($session->getSID())); self::assertFalse(HttpSession::isLocked()); } diff --git a/tests/Event/EventManagerTest.php b/tests/Event/EventManagerTest.php index 8fc996704..70c5dfd3d 100644 --- a/tests/Event/EventManagerTest.php +++ b/tests/Event/EventManagerTest.php @@ -32,6 +32,7 @@ class EventManagerTest extends \PHPUnit\Framework\TestCase $event = new EventManager(); self::assertEquals(0, $event->count()); + self::assertFalse($event->trigger('invalid')); } public function testBase() @@ -41,15 +42,12 @@ class EventManagerTest extends \PHPUnit\Framework\TestCase self::assertTrue($event->attach('group', function() { return true; }, false, false)); self::assertFalse($event->attach('group', function() { return true; }, false, false)); self::assertEquals(1, $event->count()); - - self::assertTrue($event->detach('group')); - self::assertFalse($event->trigger('group')); - self::assertEquals(0, $event->count()); } public function testReset() { $event = new EventManager(); + self::assertTrue($event->attach('group', function() { return true; }, false, true)); $event->addGroup('group', 'id1'); $event->addGroup('group', 'id2'); @@ -58,17 +56,17 @@ class EventManagerTest extends \PHPUnit\Framework\TestCase self::assertTrue($event->trigger('group', 'id2')); self::assertFalse($event->trigger('group', 'id2')); self::assertEquals(1, $event->count()); - - self::assertTrue($event->detach('group')); } public function testDetach() { $event = new EventManager(); + self::assertTrue($event->attach('group', function() { return true; }, false, true)); $event->addGroup('group', 'id1'); $event->addGroup('group', 'id2'); + self::assertEquals(1, $event->count()); self::assertTrue($event->detach('group')); self::assertEquals(0, $event->count()); self::assertFalse($event->trigger('group')); @@ -77,6 +75,7 @@ class EventManagerTest extends \PHPUnit\Framework\TestCase public function testRemove() { $event = new EventManager(); + self::assertTrue($event->attach('group1', function() { return true; }, true, false)); self::assertTrue($event->attach('group2', function() { return true; }, true, false)); self::assertEquals(2, $event->count()); diff --git a/tests/ExtensionTest.php b/tests/ExtensionTest.php index 8b97fa463..3fd423ae5 100644 --- a/tests/ExtensionTest.php +++ b/tests/ExtensionTest.php @@ -15,11 +15,28 @@ namespace phpOMS\tests; class ExtensionTest extends \PHPUnit\Framework\TestCase { - public function testExtension() + public function testExtensionMbstring() { self::assertTrue(extension_loaded('mbstring')); + } + + public function testExtensionCurl() + { self::assertTrue(extension_loaded('curl')); + } + + public function testExtensionImap() + { self::assertTrue(extension_loaded('imap')); + } + + public function testExtensionPdo() + { + self::assertTrue(extension_loaded('pdo')); + } + + public function testExtensionGD() + { self::assertTrue(extension_loaded('gd') || extension_loaded('gd2')); } } diff --git a/tests/Localization/LocalizationTest.php b/tests/Localization/LocalizationTest.php index 305c488ce..60739e5a2 100644 --- a/tests/Localization/LocalizationTest.php +++ b/tests/Localization/LocalizationTest.php @@ -16,6 +16,7 @@ namespace phpOMS\tests\Localization; use phpOMS\Localization\ISO3166TwoEnum; use phpOMS\Localization\ISO4217Enum; use phpOMS\Localization\ISO639x1Enum; +use phpOMS\Localization\ISO4217CharEnum; use phpOMS\Localization\L11nManager; use phpOMS\Localization\Localization; use phpOMS\Localization\TimeZoneEnumArray; @@ -55,7 +56,7 @@ class LocalizationTest extends \PHPUnit\Framework\TestCase self::assertTrue(ISO4217Enum::isValidValue($localization->getCurrency())); self::assertEquals('.', $localization->getDecimal()); self::assertEquals(',', $localization->getThousands()); - self::assertEquals('Y-m-d H:i:s', $localization->getDatetime()); + self::assertEquals([], $localization->getDatetime()); self::assertEquals([], $localization->getSpeed()); self::assertEquals([], $localization->getWeight()); @@ -113,11 +114,11 @@ class LocalizationTest extends \PHPUnit\Framework\TestCase $localization->setLanguage(ISO639x1Enum::_DE); self::assertEquals(ISO639x1Enum::_DE, $localization->getLanguage()); - $localization->setCurrency(ISO4217Enum::_EUR); - self::assertEquals(ISO4217Enum::_EUR, $localization->getCurrency()); + $localization->setCurrency(ISO4217CharEnum::_EUR); + self::assertEquals(ISO4217CharEnum::_EUR, $localization->getCurrency()); - $localization->setDatetime('Y-m-d H:i:s'); - self::assertEquals('Y-m-d H:i:s', $localization->getDatetime()); + $localization->setDatetime(['Y-m-d H:i:s']); + self::assertEquals(['Y-m-d H:i:s'], $localization->getDatetime()); $localization->setDecimal(','); self::assertEquals(',', $localization->getDecimal()); diff --git a/tests/Log/FileLoggerTest.php b/tests/Log/FileLoggerTest.php index 8ee028563..a9e07e858 100644 --- a/tests/Log/FileLoggerTest.php +++ b/tests/Log/FileLoggerTest.php @@ -55,7 +55,7 @@ class FileLoggerTest extends \PHPUnit\Framework\TestCase unlink(__DIR__ . '/test.log'); } - $log = new FileLogger(__DIR__ . '/test.log', true); + $log = new FileLogger(__DIR__ . '/test.log', false); $log->emergency(FileLogger::MSG_FULL, [ 'message' => 'msg', @@ -121,17 +121,17 @@ class FileLoggerTest extends \PHPUnit\Framework\TestCase self::assertEquals(2, $log->countLogs()['debug'] ?? 0); self::assertEquals(['0.0.0.0' => 9], $log->getHighestPerpetrator()); - self::assertEquals([5, 6, 7, 8, 9], array_keys($log->get(5, 1))); + self::assertEquals([6, 7, 8, 9, 10], array_keys($log->get(5, 1))); self::assertEquals('alert', $log->getByLine(2)['level']); ob_start(); - $log->console(FileLogger::MSG_FULL, false, [ + $log->console(FileLogger::MSG_FULL, true, [ 'message' => 'msg', 'line' => 11, 'file' => FileLoggerTest::class, ]); $ob = ob_get_clean(); - self::assertEquals(2, $log->countLogs()['info'] ?? 0); + self::assertEquals(1, $log->countLogs()['info'] ?? 0); self::assertTrue(stripos($ob, 'msg;') !== false); ob_start(); @@ -165,7 +165,7 @@ class FileLoggerTest extends \PHPUnit\Framework\TestCase { self::assertTrue(FileLogger::startTimeLog('test')); self::assertFalse(FileLogger::startTimeLog('test')); - self::assertGreaterThan(0, FileLogger::endTimeLog('test')); + self::assertGreaterThan(0.0, FileLogger::endTimeLog('test')); } public static function tearDownAfterClass() diff --git a/tests/Math/Matrix/CholeskyDecompositionTest.php b/tests/Math/Matrix/CholeskyDecompositionTest.php index 8d433f07c..ee9773f8c 100644 --- a/tests/Math/Matrix/CholeskyDecompositionTest.php +++ b/tests/Math/Matrix/CholeskyDecompositionTest.php @@ -36,11 +36,23 @@ class CholeskyDecompositionTest extends \PHPUnit\Framework\TestCase [-1, 1, 3], ], $cholesky->getL()->toArray(), '', 0.2); + self::assertTrue($cholesky->isSpd()); + } + + public function testSolve() + { + $A = new Matrix(); + $A->setMatrix([ + [25, 15, -5], + [15, 17, 0], + [-5, 0, 11], + ]); + + $cholesky = new CholeskyDecomposition($A); + $vec = new Vector(); $vec->setMatrix([[40], [49], [28]]); self::assertEquals([[1], [2], [3]], $cholesky->solve($vec)->toArray(), '', 0.2); - - self::assertTrue($cholesky->isSpd()); } /** diff --git a/tests/Math/Matrix/QRDecompositionTest.php b/tests/Math/Matrix/QRDecompositionTest.php new file mode 100644 index 000000000..7c473c25f --- /dev/null +++ b/tests/Math/Matrix/QRDecompositionTest.php @@ -0,0 +1,69 @@ +setMatrix([ + [12, -51, 4], + [6, 167, -68], + [-4, 24, -41], + ]); + + $QR = new QRDecomposition($A); + + self::assertTrue($QR->isFullRank()); + + self::assertEquals([ + [12, -69, -58 / 5], + [6, 158, 6 / 5], + [-4, 30, -33], + ], $QR->getH()->toArray(), '', 0.2); + + self::assertEquals([ + [6 / 7, -69 / 175, -58 / 175], + [3 / 7, 158 / 175, 6 / 175], + [-2 / 7, 6 / 35, -33 / 35], + ], $QR->getQ()->toArray(), '', 0.2); + + self::assertEquals([ + [14, 21, -14], + [0, 175, -70], + [0, 0, 35], + ], $QR->getR()->toArray(), '', 0.2); + }*/ + + public function testSolve() + { + $A = new Matrix(); + $A->setMatrix([ + [25, 15, -5], + [15, 17, 0], + [-5, 0, 11], + ]); + + $QR = new QRDecomposition($A); + + $vec = new Vector(); + $vec->setMatrix([[40], [49], [28]]); + self::assertEquals([[1], [2], [3]], $QR->solve($vec)->toArray(), '', 0.2); + } +} diff --git a/tests/Math/Number/ComplexTest.php b/tests/Math/Number/ComplexTest.php index 15d2dc002..fa3b584fe 100644 --- a/tests/Math/Number/ComplexTest.php +++ b/tests/Math/Number/ComplexTest.php @@ -32,37 +32,75 @@ class ComplexTest extends \PHPUnit\Framework\TestCase self::assertEquals(2, $cpl->im()); } - public function testBasics() + public function testAdd() { $cpl1 = new Complex(2, 3); $cpl2 = new Complex(3, 4); self::assertEquals('5.00 + 7.00i', $cpl1->add($cpl2)->render()); self::assertEquals('6.00 + 3.00i', $cpl1->add(4)->render()); + } + + public function testSub() + { + $cpl1 = new Complex(2, 3); + $cpl2 = new Complex(3, 4); self::assertEquals('-1.00 - 1.00i', $cpl1->sub($cpl2)->render()); self::assertEquals('-2.00 + 3.00i', $cpl1->sub(4)->render()); + } + + public function testMult() + { + $cpl1 = new Complex(2, 3); + $cpl2 = new Complex(3, 4); self::assertEquals('-6.00 + 17.00i', $cpl1->mult($cpl2)->render()); self::assertEquals('8.00 + 12.00i', $cpl1->mult(4)->render()); + } + + public function testDiv() + { + $cpl1 = new Complex(2, 3); + $cpl2 = new Complex(3, 4); self::assertEquals('0.72 + 0.04i', $cpl1->div($cpl2)->render(2)); self::assertEquals('0.50 + 0.75i', $cpl1->div(4)->render(2)); } - public function testSpecial() + public function testConjugate() { $cpl = new Complex(4, 3); self::assertEquals('4 - 3i', $cpl->conjugate()->render(0)); + } + + public function testReciprocal() + { + $cpl = new Complex(4, 3); + self::assertEquals('0.16 - 0.12i', $cpl->reciprocal()->render(2)); + } + + public function testPower() + { + $cpl = new Complex(4, 3); self::assertEquals('7.00 + 24.00i', $cpl->square()->render()); self::assertEquals('7.00 + 24.00i', $cpl->pow(2)->render()); self::assertEquals('-44.00 + 117.00i', $cpl->pow(3)->render()); + } + + public function testAbs() + { + $cpl = new Complex(4, 3); self::assertEquals(5, $cpl->abs(), '', 0.01); + } + public function testSqrt() + { + $cpl = new Complex(4, 3); self::assertEquals('2.12 + 0.71i', $cpl->sqrt()->render()); $cpl2 = new Complex(-1, 3); diff --git a/tests/Math/Number/IntegerTest.php b/tests/Math/Number/IntegerTest.php index 5d7d02a62..707647462 100644 --- a/tests/Math/Number/IntegerTest.php +++ b/tests/Math/Number/IntegerTest.php @@ -17,16 +17,22 @@ use phpOMS\Math\Number\Integer; class IntegerTest extends \PHPUnit\Framework\TestCase { - public function testInteger() + public function testIsInteger() { self::assertTrue(Integer::isInteger(4)); self::assertFalse(Integer::isInteger(1.0)); self::assertFalse(Integer::isInteger('3')); + } + public function testFactorization() + { self::assertArraySubset([2, 2, 5, 5], Integer::trialFactorization(100)); self::assertArraySubset([2], Integer::trialFactorization(2)); self::assertEquals([], Integer::trialFactorization(1)); + } + public function testOther() + { self::assertEquals(101, Integer::pollardsRho(10403, 2, 1, 2, 2)); self::assertEquals([59, 101], Integer::fermatFactor(5959)); diff --git a/tests/Math/Number/NaturalTest.php b/tests/Math/Number/NaturalTest.php index 3be1de107..1b1606922 100644 --- a/tests/Math/Number/NaturalTest.php +++ b/tests/Math/Number/NaturalTest.php @@ -17,7 +17,7 @@ use phpOMS\Math\Number\Natural; class NaturalTest extends \PHPUnit\Framework\TestCase { - public function testNatural() + public function testIsNatural() { self::assertTrue(Natural::isNatural(1235)); self::assertTrue(Natural::isNatural(0)); diff --git a/tests/Math/Number/NumbersTest.php b/tests/Math/Number/NumbersTest.php index a2ec0a445..e8a4c0945 100644 --- a/tests/Math/Number/NumbersTest.php +++ b/tests/Math/Number/NumbersTest.php @@ -37,7 +37,10 @@ class NumbersTest extends \PHPUnit\Framework\TestCase self::assertTrue(Numbers::isSquare(81)); self::assertTrue(Numbers::isSquare(6561)); self::assertFalse(Numbers::isSquare(5545348)); + } + public function testZeroCounting() + { self::assertEquals(3, Numbers::countTrailingZeros(1000)); self::assertEquals(5, Numbers::countTrailingZeros(12300000)); } diff --git a/tests/Math/Parser/EvaluatorTest.php b/tests/Math/Parser/EvaluatorTest.php index a3b4729f5..6adfadd34 100644 --- a/tests/Math/Parser/EvaluatorTest.php +++ b/tests/Math/Parser/EvaluatorTest.php @@ -17,8 +17,11 @@ use phpOMS\Math\Parser\Evaluator; class EvaluatorTest extends \PHPUnit\Framework\TestCase { - public function testPlaceholder() + public function testBasicEvaluation() { - self::markTestIncomplete(); + self::assertEquals(4.5, Evaluator::evaluate('3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3 + 1.5'), '', 2); + self::assertEquals(4.5, Evaluator::evaluate('3+4*2/(1-5)^2^3+1.5'), '', 2); + self::assertEquals(null, Evaluator::evaluate('invalid')); + self::assertEquals(null, Evaluator::evaluate('3+4*2/(1-5^2^3+1.5')); } } diff --git a/tests/Module/ModuleFactoryTest.php b/tests/Module/ModuleFactoryTest.php index 960c45d8f..9436b5264 100644 --- a/tests/Module/ModuleFactoryTest.php +++ b/tests/Module/ModuleFactoryTest.php @@ -17,11 +17,17 @@ require_once __DIR__ . '/../Autoloader.php'; use phpOMS\ApplicationAbstract; use phpOMS\Module\ModuleFactory; +use phpOMS\Module\NullModule; class ModuleFactoryTest extends \PHPUnit\Framework\TestCase { public function testFactory() { - self::assertInstanceOf(\Modules\Admin\Controller::class, ModuleFactory::getInstance('Admin', new class extends ApplicationAbstract {})); + $instance = NullModule::class; + if (\file_exists(__DIR__ . '/../../../Modules')) { + $instance = \Modules\Admin\Controller::class; + } + + self::assertInstanceOf($instance, ModuleFactory::getInstance('Admin', new class extends ApplicationAbstract {})); } } diff --git a/tests/Router/RouterTest.php b/tests/Router/RouterTest.php index 5541dfcdd..ab2f41333 100644 --- a/tests/Router/RouterTest.php +++ b/tests/Router/RouterTest.php @@ -75,13 +75,4 @@ class RouterTest extends \PHPUnit\Framework\TestCase $router->route('http://test.com/backends/admin/settings/general/something?test', RouteVerb::GET) ); } - - /** - * @expectedException \InvalidArgumentException - */ - public function testInvalidRequestType() - { - $router = new Router(); - $router->route([]); - } } diff --git a/tests/Uri/UriFactoryTest.php b/tests/Uri/UriFactoryTest.php index fcf98da43..b45a44514 100644 --- a/tests/Uri/UriFactoryTest.php +++ b/tests/Uri/UriFactoryTest.php @@ -66,7 +66,7 @@ class UriFactoryTest extends \PHPUnit\Framework\TestCase public function testBuilder() { - $uri = 'www.test-uri.com?id={@ID}&test={.mTest}&two={/path}&hash={#hash}&none=#none&found={/not}&v={/valid2}'; + $uri = 'www.test-uri.com?id={@ID}&test={.mTest}&two={/path}&hash={#hash}&none=#none&found={/not}?v={/valid2}'; $vars = [ '@ID' => 1, diff --git a/tests/Utils/Converter/NumericTest.php b/tests/Utils/Converter/NumericTest.php index ffee92f23..ef30364e2 100644 --- a/tests/Utils/Converter/NumericTest.php +++ b/tests/Utils/Converter/NumericTest.php @@ -28,6 +28,17 @@ class NumericTest extends \PHPUnit\Framework\TestCase self::assertEquals('XI', Numeric::arabicToRoman(11)); } + public function testAlphaNumeric() + { + self::assertEquals(0, Numeric::alphaToNumeric('A')); + self::assertEquals(1, Numeric::alphaToNumeric('B')); + self::assertEquals(53, Numeric::alphaToNumeric('BB')); + + self::assertEquals('A', Numeric::numericToAlpha(0)); + self::assertEquals('B', Numeric::numericToAlpha(1)); + self::assertEquals('BB', Numeric::numericToAlpha(53)); + } + public function testBase() { self::assertEquals('443', Numeric::convertBase('123', '0123456789', '01234')); diff --git a/tests/Utils/Git/CommitTest.php b/tests/Utils/Git/CommitTest.php index 0adc742de..689531b6a 100644 --- a/tests/Utils/Git/CommitTest.php +++ b/tests/Utils/Git/CommitTest.php @@ -34,7 +34,7 @@ class CommitTest extends \PHPUnit\Framework\TestCase self::assertInstanceOf('\DateTime', $commit->getDate()); } - public function testGetSet() + public function testAddRemoveFile() { $commit = new Commit(); @@ -51,21 +51,51 @@ class CommitTest extends \PHPUnit\Framework\TestCase self::assertEquals([ '/some/file/path2' => [] ], $commit->getFiles()); + } + + public function testMessage() + { + $commit = new Commit(); $commit->setMessage('My Message'); self::assertEquals('My Message', $commit->getMessage()); + } + + public function testAuthor() + { + $commit = new Commit(); $commit->setAuthor(new Author('Orange')); self::assertEquals('Orange', $commit->getAuthor()->getName()); + } + + public function testBranch() + { + $commit = new Commit(); $commit->setBranch(new Branch('develop')); self::assertEquals('develop', $commit->getBranch()->getName()); + } + + public function testTag() + { + $commit = new Commit(); $commit->setTag(new Tag('1.0.0')); self::assertEquals('1.0.0', $commit->getTag()->getName()); + } + + public function testDate() + { + $commit = new Commit(); $commit->setDate($date = new \DateTime('now')); self::assertEquals($date->format('Y-m-d'), $commit->getDate()->format('Y-m-d')); + } + + public function testRepository() + { + $commit = new Commit(); $commit->setRepository(new Repository(realpath(__DIR__ . '/../../../'))); self::assertEquals(realpath(__DIR__ . '/../../../'), $commit->getRepository()->getPath()); diff --git a/tests/Utils/IO/Csv/CsvDatabaseMapperTest.php b/tests/Utils/IO/Csv/CsvDatabaseMapperTest.php deleted file mode 100644 index 48a9fedab..000000000 --- a/tests/Utils/IO/Csv/CsvDatabaseMapperTest.php +++ /dev/null @@ -1,24 +0,0 @@ -xss
- +