From 642b74ad22f27b1b945bad8f63c72ce64e20c35a Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 15 Mar 2024 20:24:39 +0000 Subject: [PATCH] code fixes --- Ai/Ocr/Tesseract/TesseractOcr.php | 2 +- Algorithm/Clustering/AffinityPropagation.php | 10 +- .../Clustering/AgglomerativeClustering.php | 32 ++++++ Algorithm/Clustering/Birch.php | 31 ++++++ Algorithm/Clustering/DivisiveClustering.php | 31 ++++++ Algorithm/Clustering/Kmeans.php | 4 +- Algorithm/Clustering/SpectralClustering.php | 31 ++++++ .../JobScheduling/v2/Dependency/Material.php | 28 +++++ .../v2/Dependency/Qualification.php | 28 +++++ Algorithm/JobScheduling/v2/Job.php | 70 +++++++++++- Algorithm/JobScheduling/v2/ScheduleQueue.php | 68 +++++++++++- Algorithm/Rating/TrueSkill.php | 44 +++++++- Algorithm/Rating/TrueSkillFactoryGraph.php | 28 +++++ Api/Shipping/ShippingFactory.php | 2 +- .../BayesianPersonalizedRanking.php | 27 ++++- Business/Warehouse/OrderSuggestion.php | 10 -- .../Database/Mapper/DataMapperAbstract.php | 15 +++ .../Database/Mapper/DataMapperFactory.php | 11 +- DataStorage/Database/Mapper/ReadMapper.php | 10 +- DataStorage/Database/Mapper/UpdateMapper.php | 96 ++++++++++++---- DataStorage/Database/Mapper/WriteMapper.php | 48 +++++--- DataStorage/Database/Query/Builder.php | 2 +- DataStorage/Database/Query/ColumnName.php | 13 +++ DataStorage/Database/Query/Concat.php | 15 ++- .../Database/Query/Grammar/Grammar.php | 4 +- Localization/ISO4217CharEnum.php | 4 + Localization/ISO4217DecimalEnum.php | 4 + Localization/ISO4217Enum.php | 4 + Localization/ISO4217NumEnum.php | 6 + Localization/ISO4217SubUnitEnum.php | 4 + Localization/ISO4217SymbolEnum.php | 10 +- Localization/ISO4217Trait.php | 14 +-- Math/Functions/Functions.php | 10 ++ Message/Mail/Email.php | 48 ++++++-- Message/Mail/MailHandler.php | 2 - Message/Mail/MessageInterface.php | 40 ------- Message/ResponseAbstract.php | 4 +- Module/ModuleManager.php | 10 +- Module/StatusAbstract.php | 2 + Stdlib/Base/Enum.php | 6 +- Stdlib/Base/FloatInt.php | 41 ++++--- Stdlib/Base/SmartDateTime.php | 25 +++-- Uri/HttpUri.php | 6 +- Utils/Parser/Html/HtmlParser.php | 8 +- Utils/Parser/Markdown/Markdown.php | 104 +++++++++++++----- .../Parser/Spreadsheet/SpreadsheetParser.php | 2 +- Utils/Parser/Xml/XmlParser.php | 29 +++-- Utils/RnG/Number.php | 20 ++++ .../SpreadsheetDatabaseMapperTest.php | 48 ++++---- tests/Views/ViewTest.php | 1 - 50 files changed, 879 insertions(+), 233 deletions(-) delete mode 100755 Message/Mail/MessageInterface.php diff --git a/Ai/Ocr/Tesseract/TesseractOcr.php b/Ai/Ocr/Tesseract/TesseractOcr.php index 36624a9b1..03aaf34c6 100755 --- a/Ai/Ocr/Tesseract/TesseractOcr.php +++ b/Ai/Ocr/Tesseract/TesseractOcr.php @@ -101,7 +101,7 @@ final class TesseractOcr ))); if ($dpi < 300) { - $split = \explode('.', $image); + $split = \explode('.', $image); $extension = \end($split); SystemUtils::runProc( diff --git a/Algorithm/Clustering/AffinityPropagation.php b/Algorithm/Clustering/AffinityPropagation.php index 0b03a7c4c..489a8b6e8 100644 --- a/Algorithm/Clustering/AffinityPropagation.php +++ b/Algorithm/Clustering/AffinityPropagation.php @@ -116,8 +116,8 @@ final class AffinityPropagation implements ClusteringInterface $n = \count($points); $this->similarityMatrix = $this->createSimilarityMatrix($points); - $this->responsibilityMatrix = clone $this->similarityMatrix; - $this->availabilityMatrix = clone $this->similarityMatrix; + $this->responsibilityMatrix = $this->similarityMatrix; + $this->availabilityMatrix = $this->similarityMatrix; for ($c = 0; $c < $iterations; ++$c) { for ($i = 0; $i < $n; ++$i) { @@ -188,8 +188,8 @@ final class AffinityPropagation implements ClusteringInterface /** * Find the nearest group for a point * - * @param array $similarityMatrix Similarity matrix - * @param int $point Point id in the similarity matrix to compare + * @param array> $similarityMatrix Similarity matrix + * @param int $point Point id in the similarity matrix to compare * * @return int * @@ -215,7 +215,7 @@ final class AffinityPropagation implements ClusteringInterface */ public function cluster(PointInterface $point) : ?PointInterface { - $points = clone $this->points; + $points = $this->points; $points[] = $point; $similarityMatrix = $this->createSimilarityMatrix($points); diff --git a/Algorithm/Clustering/AgglomerativeClustering.php b/Algorithm/Clustering/AgglomerativeClustering.php index 10002ffdb..f5176fecf 100644 --- a/Algorithm/Clustering/AgglomerativeClustering.php +++ b/Algorithm/Clustering/AgglomerativeClustering.php @@ -119,4 +119,36 @@ final class AgglomerativeClustering implements ClusteringInterface return $distance / \count($setA) / \count($setB); } + + /** + * {@inheritdoc} + */ + public function getCentroids() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getClusters() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function cluster(PointInterface $point) : ?PointInterface + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getNoise() : array + { + return []; + } } diff --git a/Algorithm/Clustering/Birch.php b/Algorithm/Clustering/Birch.php index a941a91aa..760c7d0a1 100644 --- a/Algorithm/Clustering/Birch.php +++ b/Algorithm/Clustering/Birch.php @@ -27,4 +27,35 @@ namespace phpOMS\Algorithm\Clustering; */ final class Birch implements ClusteringInterface { + /** + * {@inheritdoc} + */ + public function getCentroids() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getClusters() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function cluster(PointInterface $point) : ?PointInterface + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getNoise() : array + { + return []; + } } diff --git a/Algorithm/Clustering/DivisiveClustering.php b/Algorithm/Clustering/DivisiveClustering.php index aeb7aa0db..9c8818ed5 100644 --- a/Algorithm/Clustering/DivisiveClustering.php +++ b/Algorithm/Clustering/DivisiveClustering.php @@ -31,4 +31,35 @@ namespace phpOMS\Algorithm\Clustering; */ final class DivisiveClustering implements ClusteringInterface { + /** + * {@inheritdoc} + */ + public function getCentroids() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getClusters() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function cluster(PointInterface $point) : ?PointInterface + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getNoise() : array + { + return []; + } } diff --git a/Algorithm/Clustering/Kmeans.php b/Algorithm/Clustering/Kmeans.php index f78032e81..cef32fe15 100755 --- a/Algorithm/Clustering/Kmeans.php +++ b/Algorithm/Clustering/Kmeans.php @@ -269,8 +269,8 @@ final class Kmeans implements ClusteringInterface } foreach ($this->points as $point) { - $c = $this->cluster($point); - $this->clusters[$c] = $point; + $c = $this->cluster($point); + $this->clusters[$c?->name] = $point; } return $this->clusters; diff --git a/Algorithm/Clustering/SpectralClustering.php b/Algorithm/Clustering/SpectralClustering.php index 01ccd36d0..aed0e568c 100644 --- a/Algorithm/Clustering/SpectralClustering.php +++ b/Algorithm/Clustering/SpectralClustering.php @@ -27,4 +27,35 @@ namespace phpOMS\Algorithm\Clustering; */ final class SpectralClustering implements ClusteringInterface { + /** + * {@inheritdoc} + */ + public function getCentroids() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getClusters() : array + { + return []; + } + + /** + * {@inheritdoc} + */ + public function cluster(PointInterface $point) : ?PointInterface + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getNoise() : array + { + return []; + } } diff --git a/Algorithm/JobScheduling/v2/Dependency/Material.php b/Algorithm/JobScheduling/v2/Dependency/Material.php index e69de29bb..f119f69e3 100644 --- a/Algorithm/JobScheduling/v2/Dependency/Material.php +++ b/Algorithm/JobScheduling/v2/Dependency/Material.php @@ -0,0 +1,28 @@ +deadline = new \DateTime('now'); } - public function getProfit() + /** + * Get the profit of the job + * + * @return float + * + * @since 1.0.0 + */ + public function getProfit() : float { return $this->value - $this->cost; } diff --git a/Algorithm/JobScheduling/v2/ScheduleQueue.php b/Algorithm/JobScheduling/v2/ScheduleQueue.php index 1ed3995b3..4fd5352fc 100644 --- a/Algorithm/JobScheduling/v2/ScheduleQueue.php +++ b/Algorithm/JobScheduling/v2/ScheduleQueue.php @@ -24,8 +24,24 @@ namespace phpOMS\Scheduling; */ final class ScheduleQueue { + /** + * Queue + * + * @var Job[] + * @since 1.0.0 + */ public array $queue = []; + /** + * Get element from queue + * + * @param int $size Amount of elements to return + * @param int $type Priority type to use for return + * + * @return Job[] + * + * @since 1.0.0 + */ public function get(int $size = 1, int $type = PriorityMode::FIFO) : array { $jobs = []; @@ -103,11 +119,33 @@ final class ScheduleQueue return $jobs; } + /** + * Insert new element into queue + * + * @param int $id Element id + * @param Job $job Element to add + * + * @return void + * + * @since 1.0.0 + */ public function insert(int $id, Job $job) : void { $this->queue[$id] = $job; } + /** + * Pop elements from the queue. + * + * This also removes the elements from the queue + * + * @param int $size Amount of elements to return + * @param int $type Priority type to use for return + * + * @return Job[] + * + * @since 1.0.0 + */ public function pop(int $size = 1, int $type = PriorityMode::FIFO) : array { $jobs = $this->get($size, $type); @@ -118,6 +156,15 @@ final class ScheduleQueue return $jobs; } + /** + * Increases the hold counter of an element + * + * @param int $id Id of the element (0 = all elements) + * + * @return void + * + * @since 1.0.0 + */ public function bumpHold(int $id = 0) : void { if ($id === 0) { @@ -129,6 +176,16 @@ final class ScheduleQueue } } + /** + * Change the priority of an element + * + * @param int $id Id of the element (0 = all elements) + * @param float $priority Priority to increase by + * + * @return void + * + * @since 1.0.0 + */ public function adjustPriority(int $id = 0, float $priority = 0.1) : void { if ($id === 0) { @@ -140,7 +197,16 @@ final class ScheduleQueue } } - public function remove(string $id) : void + /** + * Remove an element from the queue + * + * @param int $id Id of the element + * + * @return void + * + * @since 1.0.0 + */ + public function remove(int $id) : void { unset($this->queue[$id]); } diff --git a/Algorithm/Rating/TrueSkill.php b/Algorithm/Rating/TrueSkill.php index e695262dc..8b064b456 100644 --- a/Algorithm/Rating/TrueSkill.php +++ b/Algorithm/Rating/TrueSkill.php @@ -22,8 +22,8 @@ use phpOMS\Math\Stochastic\Distribution\NormalDistribution; * @package phpOMS\Algorithm\Rating * @license OMS License 2.0 * @link https://jingga.app - * @since 1.0.0 * @see https://www.moserware.com/assets/computing-your-skill/The%20Math%20Behind%20TrueSkill.pdf + * @since 1.0.0 * * @todo Implement https://github.com/sublee/trueskill/blob/master/trueskill/__init__.py * https://github.com/Karaka-Management/phpOMS/issues/337 @@ -50,6 +50,17 @@ class TrueSkill private float $drawProbability = 0.0; + /** + * Constructor. + * + * @param null|float $mu Mu + * @param null|float $sigma Sigma + * @param null|float $beta Beta + * @param null|float $tau Tau + * @param null|float $drawProbability Draw probability + * + * @since 1.0.0 + */ public function __construct( ?float $mu = null, ?float $sigma = null, @@ -64,7 +75,18 @@ class TrueSkill $this->drawProbability = $drawProbability ?? self::DEFAULT_DRAW_PROBABILITY; } - public function winProbability(array $team1, array $team2, float $drawMargin = 0.0) + /** + * Calculate win probability + * + * @param array $team1 Team 1 + * @param array $team2 Team 2 + * @param float $drawMargin Draw margin + * + * @return float + * + * @since 1.0.0 + */ + public function winProbability(array $team1, array $team2, float $drawMargin = 0.0) : float { $sigmaSum = 0.0; $mu1 = 0.0; @@ -204,22 +226,37 @@ class TrueSkill / (NormalDistribution::getCdf($epsilon - $tAbs, 0.0, 1.0) - NormalDistribution::getCdf(-$epsilon - $tAbs, 0.0, 1.0)); } + /** + * + */ private function buildRatingLayer() : void { } + /** + * + */ private function buildPerformanceLayer() : void { } + /** + * + */ private function buildTeamPerformanceLayer() : void { } + /** + * + */ private function buildTruncLayer() : void { } + /** + * + */ private function factorGraphBuilders() { // Rating layer @@ -238,6 +275,9 @@ class TrueSkill ]; } + /** + * + */ public function rating() : void { // Start values diff --git a/Algorithm/Rating/TrueSkillFactoryGraph.php b/Algorithm/Rating/TrueSkillFactoryGraph.php index e69de29bb..22445ea52 100644 --- a/Algorithm/Rating/TrueSkillFactoryGraph.php +++ b/Algorithm/Rating/TrueSkillFactoryGraph.php @@ -0,0 +1,28 @@ +numFactors = $numFactors; @@ -47,7 +53,14 @@ final class BayesianPersonalizedRanking $this->regularization = $regularization; } - private function generateRandomFactors() + /** + * Calculate random factors + * + * @return array + * + * @since 1.0.0 + */ + private function generateRandomFactors() : array { $factors = []; for ($i = 0; $i < $this->numFactors; ++$i) { @@ -57,6 +70,9 @@ final class BayesianPersonalizedRanking return $factors; } + /** + * @todo implement + */ public function predict($userId, $itemId) { $userFactor = $this->userFactors[$userId]; $itemFactor = $this->itemFactors[$itemId]; @@ -69,6 +85,9 @@ final class BayesianPersonalizedRanking return $score; } + /** + * @todo implement + */ public function updateFactors($userId, $posItemId, $negItemId) : void { if (!isset($this->userFactors[$userId])) { diff --git a/Business/Warehouse/OrderSuggestion.php b/Business/Warehouse/OrderSuggestion.php index 62dcadeeb..22a347a75 100644 --- a/Business/Warehouse/OrderSuggestion.php +++ b/Business/Warehouse/OrderSuggestion.php @@ -24,16 +24,6 @@ namespace phpOMS\Business\Sales; */ final class OrderSuggestion { - /** - * Constructor - * - * @since 1.0.0 - * @codeCoverageIgnore - */ - private function __construct() - { - } - /** * Calculate the optimal order quantity using the Andler formula */ diff --git a/DataStorage/Database/Mapper/DataMapperAbstract.php b/DataStorage/Database/Mapper/DataMapperAbstract.php index ff212d0fc..eb07c3f7d 100755 --- a/DataStorage/Database/Mapper/DataMapperAbstract.php +++ b/DataStorage/Database/Mapper/DataMapperAbstract.php @@ -158,8 +158,23 @@ abstract class DataMapperAbstract $this->db = $db; } + /** + * Column name of the index + * + * @var string + * @since 1.0.0 + */ protected string $indexedBy = ''; + /** + * Set column name where the id is defined + * + * @param string $index Column name of the index + * + * @return self + * + * @since 1.0.0 + */ public function indexedBy(string $index) : self { $this->indexedBy = $index; diff --git a/DataStorage/Database/Mapper/DataMapperFactory.php b/DataStorage/Database/Mapper/DataMapperFactory.php index babca838a..d91f6fd48 100755 --- a/DataStorage/Database/Mapper/DataMapperFactory.php +++ b/DataStorage/Database/Mapper/DataMapperFactory.php @@ -474,15 +474,20 @@ class DataMapperFactory return static::FACTORY::createWith($data); } + /** + * Mapper uses a factory + * + * @return bool + * + * @since 1.0.0 + */ public static function hasFactory() : bool { return !empty(static::FACTORY); } /** - * Create the empty base model - * - * @param null|array $data Data to use for initialization + * Get base model class name * * @return string * diff --git a/DataStorage/Database/Mapper/ReadMapper.php b/DataStorage/Database/Mapper/ReadMapper.php index 6fec4a196..caef030fc 100755 --- a/DataStorage/Database/Mapper/ReadMapper.php +++ b/DataStorage/Database/Mapper/ReadMapper.php @@ -748,9 +748,9 @@ final class ReadMapper extends DataMapperAbstract } /** @var self $relMapper */ - $relMapper = $this->createRelationMapper($rel['mapper']::reader(db: $this->db), $member); - $relMapper->depth = $this->depth + 1; - $relMapper->type = $this->type; + $relMapper = $this->createRelationMapper($rel['mapper']::reader(db: $this->db), $member); + $relMapper->depth = $this->depth + 1; + $relMapper->type = $this->type; $relMapper->joinAlias = '_' . $member; // Here we go further into the depth of the model (e.g. a hasMany/ownsOne can again have ownsOne...) @@ -1090,8 +1090,8 @@ final class ReadMapper extends DataMapperAbstract // in this case you can get the profile by loading the profile based on the account reference column /** @var self $belongsToMapper */ - $belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member); - $belongsToMapper->depth = $this->depth + 1; + $belongsToMapper = $this->createRelationMapper($mapper::get($this->db), $member); + $belongsToMapper->depth = $this->depth + 1; $belongsToMapper->joinAlias = '_' . $member; $belongsToMapper->where( diff --git a/DataStorage/Database/Mapper/UpdateMapper.php b/DataStorage/Database/Mapper/UpdateMapper.php index db0dc76ca..a6af226df 100755 --- a/DataStorage/Database/Mapper/UpdateMapper.php +++ b/DataStorage/Database/Mapper/UpdateMapper.php @@ -181,7 +181,7 @@ final class UpdateMapper extends DataMapperAbstract \usleep(10000); $repeat = true; } - } while($repeat); + } while ($repeat); } catch (\Throwable $t) { // @codeCoverageIgnoreStart \phpOMS\Log\FileLogger::getInstance()->error( @@ -210,19 +210,48 @@ final class UpdateMapper extends DataMapperAbstract /** @var class-string $mapper */ $mapper = $this->mapper::BELONGS_TO[$propertyName]['mapper']; - if (!isset($this->with[$propertyName])) { - $id = $mapper::getObjectId($obj); + if (isset($this->with[$propertyName])) { + /** @var self $relMapper */ + $relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName); + $relMapper->depth = $this->depth + 1; - return empty($id) && $mapper::isNullModel($obj) - ? null - : $id; + $id = $relMapper->execute($obj); + + if (!isset($this->mapper::OWNS_ONE[$propertyName]['by'])) { + return $id; + } + + if ($this->mapper::OWNS_ONE[$propertyName]['private'] ?? false) { + $refClass = new \ReflectionClass($obj); + $refProp = $refClass->getProperty($this->mapper::OWNS_ONE[$propertyName]['by']); + $value = $refProp->getValue($obj); + } else { + $value = $obj->{$this->mapper::OWNS_ONE[$propertyName]['by']}; + } + + return $value; } - /** @var self $relMapper */ - $relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName); - $relMapper->depth = $this->depth + 1; + if (isset($this->mapper::BELONGS_TO[$propertyName]['by'])) { + // has by (obj is stored as a different model e.g. model = profile but reference/db is account) + if ($this->mapper::BELONGS_TO[$propertyName]['private'] ?? false) { + $refClass = new \ReflectionClass($obj); + $refProp = $refClass->getProperty($this->mapper::BELONGS_TO[$propertyName]['by']); + $obj = $refProp->getValue($obj); + } else { + $obj = $obj->{$this->mapper::BELONGS_TO[$propertyName]['by']}; + } - return $relMapper->execute($obj); + if (!\is_object($obj)) { + return $obj; + } + } + + $id = $mapper::getObjectId($obj); + + return empty($id) && $mapper::isNullModel($obj) + ? null + : $id; } /** @@ -240,19 +269,48 @@ final class UpdateMapper extends DataMapperAbstract /** @var class-string $mapper */ $mapper = $this->mapper::OWNS_ONE[$propertyName]['mapper']; - if (!isset($this->with[$propertyName])) { - $id = $mapper::getObjectId($obj); + if (isset($this->with[$propertyName])) { + /** @var self $relMapper */ + $relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName); + $relMapper->depth = $this->depth + 1; - return empty($id) && $mapper::isNullModel($obj) - ? null - : $id; + $id = $relMapper->execute($obj); + + if (!isset($this->mapper::OWNS_ONE[$propertyName]['by'])) { + return $id; + } + + if ($this->mapper::OWNS_ONE[$propertyName]['private'] ?? false) { + $refClass = new \ReflectionClass($obj); + $refProp = $refClass->getProperty($this->mapper::OWNS_ONE[$propertyName]['by']); + $value = $refProp->getValue($obj); + } else { + $value = $obj->{$this->mapper::OWNS_ONE[$propertyName]['by']}; + } + + return $value; } - /** @var self $relMapper */ - $relMapper = $this->createRelationMapper($mapper::update(db: $this->db), $propertyName); - $relMapper->depth = $this->depth + 1; + if (isset($this->mapper::OWNS_ONE[$propertyName]['by'])) { + // has by (obj is stored as a different model e.g. model = profile but reference/db is account) + if ($this->mapper::OWNS_ONE[$propertyName]['private'] ?? false) { + $refClass = new \ReflectionClass($obj); + $refProp = $refClass->getProperty($this->mapper::OWNS_ONE[$propertyName]['by']); + $obj = $refProp->getValue($obj); + } else { + $obj = $obj->{$this->mapper::OWNS_ONE[$propertyName]['by']}; + } - return $relMapper->execute($obj); + if (!\is_object($obj)) { + return $obj; + } + } + + $id = $mapper::getObjectId($obj); + + return empty($id) && $mapper::isNullModel($obj) + ? null + : $id; } /** diff --git a/DataStorage/Database/Mapper/WriteMapper.php b/DataStorage/Database/Mapper/WriteMapper.php index a171b397a..1abbe295a 100755 --- a/DataStorage/Database/Mapper/WriteMapper.php +++ b/DataStorage/Database/Mapper/WriteMapper.php @@ -177,7 +177,7 @@ final class WriteMapper extends DataMapperAbstract \usleep(10000); $repeat = true; } - } while($repeat); + } while ($repeat); $objId = empty($id = $this->mapper::getObjectId($obj)) ? $this->db->con->lastInsertId() : $id; \settype($objId, $this->mapper::COLUMNS[$this->mapper::PRIMARYFIELD]['type']); @@ -210,19 +210,35 @@ final class WriteMapper extends DataMapperAbstract */ private function createOwnsOne(string $propertyName, object $obj) : mixed { - if (!\is_object($obj)) { - return $obj; + // @question This code prevents us from EVER creating an object with a 'by' reference since we always assume + // that it already exists -> only return the custom reference id + // See bug below. + + // @todo We might also have to handle 'column' + if (isset($this->mapper::OWNS_ONE[$propertyName]['by'])) { + // has by (obj is stored as a different model e.g. model = profile but reference/db is account) + if ($this->mapper::OWNS_ONE[$propertyName]['private'] ?? false) { + $refClass = new \ReflectionClass($obj); + $refProp = $refClass->getProperty($this->mapper::OWNS_ONE[$propertyName]['by']); + $obj = $refProp->getValue($obj); + } else { + $obj = $obj->{$this->mapper::OWNS_ONE[$propertyName]['by']}; + } + + if (!\is_object($obj)) { + return $obj; + } } /** @var class-string $mapper */ $mapper = $this->mapper::OWNS_ONE[$propertyName]['mapper']; $primaryKey = $mapper::getObjectId($obj); - if (empty($primaryKey)) { - return $mapper::create(db: $this->db)->execute($obj); - } - - return $primaryKey; + // @bug The $mapper::create() might cause a problem if 'by' is set. + // This is because we don't want to create this obj but the child obj. + return empty($primaryKey) + ? $mapper::create(db: $this->db)->execute($obj) + : $primaryKey; } /** @@ -237,13 +253,11 @@ final class WriteMapper extends DataMapperAbstract */ private function createBelongsTo(string $propertyName, object $obj) : mixed { - if (!\is_object($obj)) { - return $obj; - } - - $mapper = ''; - $primaryKey = 0; + // @question This code prevents us from EVER creating an object with a 'by' reference since we always assume + // that it already exists -> only return the custom reference id + // See bug below. + // @todo We might also have to handle 'column' if (isset($this->mapper::BELONGS_TO[$propertyName]['by'])) { // has by (obj is stored as a different model e.g. model = profile but reference/db is account) if ($this->mapper::BELONGS_TO[$propertyName]['private'] ?? false) { @@ -253,6 +267,10 @@ final class WriteMapper extends DataMapperAbstract } else { $obj = $obj->{$this->mapper::BELONGS_TO[$propertyName]['by']}; } + + if (!\is_object($obj)) { + return $obj; + } } /** @var class-string $mapper */ @@ -435,7 +453,7 @@ final class WriteMapper extends DataMapperAbstract \usleep(10000); $repeat = true; } - } while($repeat); + } while ($repeat); } catch (\Throwable $t) { // @codeCoverageIgnoreStart \phpOMS\Log\FileLogger::getInstance()->error( diff --git a/DataStorage/Database/Query/Builder.php b/DataStorage/Database/Query/Builder.php index 8698e2eb6..a1bdcd017 100755 --- a/DataStorage/Database/Query/Builder.php +++ b/DataStorage/Database/Query/Builder.php @@ -1296,7 +1296,7 @@ class Builder extends BuilderAbstract * * @param string|array $columns Columns to join on * @param null|string|array $operator Comparison operator - * @param null|string|array $values Values to compare with + * @param mixed $values Values to compare with * @param string|array $boolean Concatenation * @param null|string $table Table this belongs to * diff --git a/DataStorage/Database/Query/ColumnName.php b/DataStorage/Database/Query/ColumnName.php index afe50c59e..726bce63f 100644 --- a/DataStorage/Database/Query/ColumnName.php +++ b/DataStorage/Database/Query/ColumnName.php @@ -24,8 +24,21 @@ namespace phpOMS\DataStorage\Database\Query; */ final class ColumnName { + /** + * Column name + * + * @var string + * @since 1.0.0 + */ public string $name = ''; + /** + * Constructor. + * + * @param string $name Column name + * + * @since 1.0.0 + */ public function __construct(string $name) { $this->name = $name; diff --git a/DataStorage/Database/Query/Concat.php b/DataStorage/Database/Query/Concat.php index bfe92490f..032b041f6 100644 --- a/DataStorage/Database/Query/Concat.php +++ b/DataStorage/Database/Query/Concat.php @@ -43,10 +43,21 @@ class Concat extends Builder $this->type = QueryType::SELECT; } + /** + * Columns to concat + * + * @param string $as Alias + * @param string $delim Delimiter + * @param string ...$columns Columns to concat + * + * @return void + * + * @since 1.0.0 + */ public function columns(string $as, string $delim, ...$columns) : void { $this->delim = $delim; - $this->as = $as; + $this->as = $as; $this->select($columns); } @@ -64,4 +75,4 @@ class Concat extends Builder return $query; } -} \ No newline at end of file +} diff --git a/DataStorage/Database/Query/Grammar/Grammar.php b/DataStorage/Database/Query/Grammar/Grammar.php index 051cf7752..5c1b539b4 100755 --- a/DataStorage/Database/Query/Grammar/Grammar.php +++ b/DataStorage/Database/Query/Grammar/Grammar.php @@ -295,7 +295,7 @@ class Grammar extends GrammarAbstract protected function compileWhereElement(array $element, Builder $query, bool $first = true) : string { $expression = ''; - $prefix = ''; + $prefix = ''; if (!$first) { $prefix = ' ' . \strtoupper($element['boolean']) . ' '; @@ -319,7 +319,7 @@ class Grammar extends GrammarAbstract if (empty($element['value'])) { $element['operator'] = '='; - $element['value'] = null; + $element['value'] = null; } } diff --git a/Localization/ISO4217CharEnum.php b/Localization/ISO4217CharEnum.php index f35a9a2e0..13519f4f3 100755 --- a/Localization/ISO4217CharEnum.php +++ b/Localization/ISO4217CharEnum.php @@ -44,6 +44,8 @@ class ISO4217CharEnum extends Enum public const _AZN = 'AZN'; + public const _AZM = 'AZM'; + public const _BSD = 'BSD'; public const _BBD = 'BBD'; @@ -75,7 +77,9 @@ class ISO4217CharEnum extends Enum public const _CLP = 'CLP'; public const _CNY = 'CNY'; + public const _CNH = 'CNH'; + public const _RMB = 'RMB'; public const _COP = 'COP'; diff --git a/Localization/ISO4217DecimalEnum.php b/Localization/ISO4217DecimalEnum.php index 23f758dfd..bfe602265 100755 --- a/Localization/ISO4217DecimalEnum.php +++ b/Localization/ISO4217DecimalEnum.php @@ -46,6 +46,8 @@ class ISO4217DecimalEnum extends Enum public const _AZN = 2; + public const _AZM = 2; + public const _BAM = 2; public const _BBD = 2; @@ -93,7 +95,9 @@ class ISO4217DecimalEnum extends Enum public const _CLP = 0; public const _CNY = 2; + public const _CNH = 2; + public const _RMB = 2; public const _COP = 2; diff --git a/Localization/ISO4217Enum.php b/Localization/ISO4217Enum.php index 458458b1a..c5882551b 100755 --- a/Localization/ISO4217Enum.php +++ b/Localization/ISO4217Enum.php @@ -42,6 +42,8 @@ class ISO4217Enum extends Enum public const _AZN = 'New Manats, Azerbaijan'; + public const _AZM = 'Manats, Azerbaijan'; + public const _AOA = 'Kwanza, Angolan'; public const _BSD = 'Dollars, Bahamas'; @@ -75,7 +77,9 @@ class ISO4217Enum extends Enum public const _CLP = 'Pesos, Chile'; public const _CNY = 'Yuan Renminbi, China'; + public const _CNH = 'Yuan Renminbi, China'; + public const _RMB = 'Yuan Renminbi, China'; public const _COP = 'Pesos, Colombia'; diff --git a/Localization/ISO4217NumEnum.php b/Localization/ISO4217NumEnum.php index f75c56176..cf582dfbe 100755 --- a/Localization/ISO4217NumEnum.php +++ b/Localization/ISO4217NumEnum.php @@ -46,6 +46,8 @@ class ISO4217NumEnum extends Enum public const _AZN = '944'; + public const _AZM = '944'; + public const _BAM = '977'; public const _BBD = '052'; @@ -93,7 +95,9 @@ class ISO4217NumEnum extends Enum public const _CLP = '152'; public const _CNY = '156'; + public const _CNH = '156'; + public const _RMB = '156'; public const _COP = '170'; @@ -396,5 +400,7 @@ class ISO4217NumEnum extends Enum public const _ZWL = '932'; + public const _ZWD = '716'; + use ISO4217Trait; } diff --git a/Localization/ISO4217SubUnitEnum.php b/Localization/ISO4217SubUnitEnum.php index 0bcbe52d7..896f47ddf 100755 --- a/Localization/ISO4217SubUnitEnum.php +++ b/Localization/ISO4217SubUnitEnum.php @@ -83,7 +83,9 @@ class ISO4217SubUnitEnum extends Enum public const _CLP = 100; public const _CNY = 100; + public const _CNH = 100; + public const _RMB = 100; public const _COP = 100; @@ -402,6 +404,8 @@ class ISO4217SubUnitEnum extends Enum public const _AZN = 100; + public const _AZM = 100; + public const _CRC = 100; public const _GIP = 100; diff --git a/Localization/ISO4217SymbolEnum.php b/Localization/ISO4217SymbolEnum.php index aeff629e7..9df3994a4 100755 --- a/Localization/ISO4217SymbolEnum.php +++ b/Localization/ISO4217SymbolEnum.php @@ -17,7 +17,7 @@ namespace phpOMS\Localization; use phpOMS\Stdlib\Base\Enum; /** - * Country symbols ISO list. + * Currency symbols ISO list. * * @package phpOMS\Localization * @license OMS License 2.0 @@ -42,6 +42,8 @@ class ISO4217SymbolEnum extends Enum public const _AZN = 'ман'; + public const _AZM = '₼'; + public const _AOA = 'Kz'; public const _BSD = '$'; @@ -75,7 +77,9 @@ class ISO4217SymbolEnum extends Enum public const _CLP = '$'; public const _CNY = '¥'; + public const _CNH = '¥'; + public const _RMB = '¥'; public const _COP = '$'; @@ -108,6 +112,8 @@ class ISO4217SymbolEnum extends Enum public const _GIP = '£'; + public const _GMD = 'GMD'; + public const _GTQ = 'Q'; public const _GGP = '£'; @@ -302,7 +308,7 @@ class ISO4217SymbolEnum extends Enum public const _HTG = 'HTG'; - public const _IQD = 'IQD'; + public const _IQD = 'ع'; public const _JOD = 'JOD'; diff --git a/Localization/ISO4217Trait.php b/Localization/ISO4217Trait.php index 65cf44fc2..3696542a2 100644 --- a/Localization/ISO4217Trait.php +++ b/Localization/ISO4217Trait.php @@ -29,7 +29,7 @@ trait ISO4217Trait * * @param string $country Country 2 code * - * @return array + * @return string * * @since 1.0.0 */ @@ -65,7 +65,7 @@ trait ISO4217Trait case ISO3166TwoEnum::_AUT: return self::_EUR; case ISO3166TwoEnum::_AZE: - return self::_AZM; + return self::_AZN; case ISO3166TwoEnum::_PRT: return self::_EUR; case ISO3166TwoEnum::_BHS: @@ -235,7 +235,7 @@ trait ISO4217Trait case ISO3166TwoEnum::_IDN: return self::_IDR; case ISO3166TwoEnum::_IRQ: - return self::_NID; + return self::_IQD; case ISO3166TwoEnum::_IRL: return self::_EUR; case ISO3166TwoEnum::_ISR: @@ -325,7 +325,7 @@ trait ISO4217Trait case ISO3166TwoEnum::_MAR: return self::_MAD; case ISO3166TwoEnum::_MOZ: - return self::_MZM; + return self::_MZN; case ISO3166TwoEnum::_NAM: return self::_NAD; case ISO3166TwoEnum::_NPL: @@ -371,7 +371,7 @@ trait ISO4217Trait case ISO3166TwoEnum::_REU: return self::_EUR; case ISO3166TwoEnum::_ROU: - return self::_ROL; + return self::_RON; case ISO3166TwoEnum::_RUS: return self::_RUB; case ISO3166TwoEnum::_RWA: @@ -417,7 +417,7 @@ trait ISO4217Trait case ISO3166TwoEnum::_VCT: return self::_XCD; case ISO3166TwoEnum::_SUR: - return self::_SRG; + return self::_SRD; case ISO3166TwoEnum::_SWZ: return self::_SZL; case ISO3166TwoEnum::_SWE: @@ -465,7 +465,7 @@ trait ISO4217Trait case ISO3166TwoEnum::_VAT: return self::_EUR; case ISO3166TwoEnum::_VEN: - return self::_VEB; + return self::_VEF; case ISO3166TwoEnum::_VNM: return self::_VND; case ISO3166TwoEnum::_WLF: diff --git a/Math/Functions/Functions.php b/Math/Functions/Functions.php index 153a9e3a7..ff087f23f 100755 --- a/Math/Functions/Functions.php +++ b/Math/Functions/Functions.php @@ -196,6 +196,16 @@ final class Functions return $a % $b; } + /** + * Modular implementation for float values + * + * @param float $a a + * @param float $b b + * + * @return float + * + * @since 1.0.0 + */ public static function modFloat(float $a, float $b) : float { return $a - ((int) ($a / $b)) * $b; diff --git a/Message/Mail/Email.php b/Message/Mail/Email.php index 389258b2f..684d46253 100755 --- a/Message/Mail/Email.php +++ b/Message/Mail/Email.php @@ -34,7 +34,7 @@ use phpOMS\Validation\Network\Email as EmailValidator; * @link https://jingga.app * @since 1.0.0 */ -class Email implements MessageInterface +class Email { /** * Mailer name. @@ -462,11 +462,25 @@ class Email implements MessageInterface $this->contentType = $isHtml ? MimeType::M_HTML : MimeType::M_TEXT; } + /** + * Get content type + * + * @return string + * + * @since 1.0.0 + */ public function getContentType() : string { return $this->contentType; } + /** + * Is html content type? + * + * @return bool + * + * @since 1.0.0 + */ public function isHtml() : bool { return $this->contentType === MimeType::M_HTML; @@ -568,10 +582,10 @@ class Email implements MessageInterface * * @since 1.0.0 */ - public static function parseAddresses(string $addrstr, bool $useimap = true, string $charset = CharsetType::ISO_8859_1) : array + public static function parseAddresses(string $addrstr, bool $useImap = true, string $charset = CharsetType::ISO_8859_1) : array { $addresses = []; - if ($useimap && \function_exists('imap_rfc822_parse_adrlist')) { + if ($useImap && \function_exists('imap_rfc822_parse_adrlist')) { $list = \imap_rfc822_parse_adrlist($addrstr, ''); foreach ($list as $address) { if (($address->host !== '.SYNTAX-ERROR.') @@ -623,6 +637,15 @@ class Email implements MessageInterface return $addresses; } + /** + * Parse email template. + * + * Replaces placeholders with content + * + * @return void + * + * @since 1.0.0 + */ public function parseTemplate() : void { if (empty($this->template)) { @@ -778,7 +801,7 @@ class Email implements MessageInterface $result .= 'X-Mailer: ' . self::XMAILER . self::$LE; if ($this->confirmationAddress !== '') { - $result .= 'Disposition-Notification-To: ' . '<' . $this->confirmationAddress . '>' . self::$LE; + $result .= 'Disposition-Notification-To: <' . $this->confirmationAddress . '>' . self::$LE; } // Add custom headers @@ -1283,10 +1306,10 @@ class Email implements MessageInterface $mime[] = empty($encodedName) ? \sprintf('Content-Disposition: %s%s', $disposition, self::$LE . self::$LE) : \sprintf('Content-Disposition: %s; filename=%s%s', - $disposition, - self::quotedString($encodedName), - self::$LE . self::$LE - ); + $disposition, + self::quotedString($encodedName), + self::$LE . self::$LE + ); } else { $mime[] = self::$LE; } @@ -1471,7 +1494,7 @@ class Email implements MessageInterface * * @return void * - * @return 1.0.0 + * @since 1.0.0 */ public function setWordWrap() : void { @@ -1626,9 +1649,9 @@ class Email implements MessageInterface $matchcount = \preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); break; - /* @noinspection PhpMissingBreakStatementInspection */ case 'comment': $matchcount = \preg_match_all('/[()"]/', $str, $matches); + // no break case 'text': default: $matchcount += \preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); @@ -1703,6 +1726,7 @@ class Email implements MessageInterface break; case 'comment': $pattern = '\(\)"'; + // no break case 'text': default: // Replace every high ascii, control, =, ? and _ characters @@ -2122,7 +2146,7 @@ class Email implements MessageInterface /** * Normalize line breaks in a string. * - * @param string $text + * @param string $text Text to normalize * @param string $breaktype What kind of line break to use; defaults to self::$LE * * @return string @@ -2210,7 +2234,7 @@ class Email implements MessageInterface /** * Generate a DKIM signature. * - * @param string $signHeader + * @param string $signHeader Sign header * * @return string The DKIM signature value * diff --git a/Message/Mail/MailHandler.php b/Message/Mail/MailHandler.php index 5baabf506..33d188ed0 100755 --- a/Message/Mail/MailHandler.php +++ b/Message/Mail/MailHandler.php @@ -20,7 +20,6 @@ namespace phpOMS\Message\Mail; use phpOMS\Security\Guard; use phpOMS\System\SystemUtils; -use phpOMS\Utils\StringUtils; use phpOMS\Validation\Network\Email as EmailValidator; use phpOMS\Validation\Network\Hostname; @@ -398,7 +397,6 @@ class MailHandler * * @param string $to To * @param Email $mail Mail - * @param string $body Message Body * @param string $header Additional Header(s) * @param null|string $params Params * diff --git a/Message/Mail/MessageInterface.php b/Message/Mail/MessageInterface.php deleted file mode 100755 index 38dd764f2..000000000 --- a/Message/Mail/MessageInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -> * @since 1.0.0 */ private array $running = []; @@ -678,9 +678,15 @@ final class ModuleManager // Handle providing->receiving foreach ($this->running as $mName => $controllers) { $controller = \reset($controllers); + if ($controller === false) { + continue; + } foreach ($controller::$providing as $providing) { $ctrl = \reset($this->running[$providing]); + if ($ctrl === false) { + continue; + } if (!\in_array($mName, $ctrl->receiving)) { $ctrl->receiving[] = $mName; @@ -724,7 +730,7 @@ final class ModuleManager ) { try { /** @var ModuleAbstract $obj */ - $obj = new $class($this->app); + $obj = new $class($this->app); $this->running[$module][$class] = $obj; } catch (\Throwable $_) { $this->running[$module][$class] = new NullModule(); diff --git a/Module/StatusAbstract.php b/Module/StatusAbstract.php index 7ec93d6ee..7cf27501f 100755 --- a/Module/StatusAbstract.php +++ b/Module/StatusAbstract.php @@ -134,6 +134,7 @@ abstract class StatusAbstract * Init routes and hooks. * * @param ModuleInfo $info Module info + * @param string $type Is 'Routes' or 'Hooks' * @param null|ApplicationInfo $appInfo Application info * * @return void @@ -204,6 +205,7 @@ abstract class StatusAbstract * Deactivate routes and hooks. * * @param ModuleInfo $info Module info + * @param string $type Is 'Routes' or 'Hooks' * @param null|ApplicationInfo $appInfo Application info * * @return void diff --git a/Stdlib/Base/Enum.php b/Stdlib/Base/Enum.php index 7cbd47f21..1e873d0fc 100755 --- a/Stdlib/Base/Enum.php +++ b/Stdlib/Base/Enum.php @@ -50,9 +50,11 @@ abstract class Enum * * Checking if a given value is part of this enum * - * @param mixed $value Value to check + * @template T * - * @return mixed + * @param T $value Value to check + * + * @return null|T * * @since 1.0.0 */ diff --git a/Stdlib/Base/FloatInt.php b/Stdlib/Base/FloatInt.php index cf8049ecd..82f08a84e 100755 --- a/Stdlib/Base/FloatInt.php +++ b/Stdlib/Base/FloatInt.php @@ -23,6 +23,8 @@ use phpOMS\Contract\SerializableInterface; * @license OMS License 2.0 * @link https://jingga.app * @since 1.0.0 + * + * @todo The naming of functions in this class is atrocious (getInt, getFloat, getNormalized, ...). */ class FloatInt implements SerializableInterface { @@ -34,6 +36,12 @@ class FloatInt implements SerializableInterface */ public const MAX_DECIMALS = 4; + /** + * Divisor to get original value. + * + * @var int + * @since 1.0.0 + */ public const DIVISOR = 10000; /** @@ -92,7 +100,7 @@ class FloatInt implements SerializableInterface public static function toInt(string $value, string $thousands = ',', string $decimal = '.') : int { $newValue = $value; - $len = \strlen($value); + $len = \strlen($value); $decimalPos = \strrpos($value, $decimal); if ($decimalPos === false) { @@ -140,20 +148,18 @@ class FloatInt implements SerializableInterface return $this; } + /** + * Returns the value as float + * + * @return float + * + * @since 1.0.0 + */ public function getNormalizedValue() : float { return $this->value / self::DIVISOR; } - public function guessScalarValue() : int|float - { - $divider = self::DIVISOR; - - return $this->value % $divider === 0 - ? (int) ($this->value / $divider) - : (float) ($this->value / $divider); - } - /** * Get money. * @@ -382,15 +388,24 @@ class FloatInt implements SerializableInterface return $this; } + /** + * Identify the numeric format of a string + * + * @param string $str String representation + * + * @return null|array + * + * @since 1.0.0 + */ public static function identifyNumericFormat(string $str) : ?array { - $commaPos = \strrpos($str, ','); + $commaPos = \strrpos($str, ','); $periodPos = \strrpos($str, '.'); if ($commaPos !== false && $periodPos !== false) { return [ 'thousands' => $commaPos < $periodPos ? ',' : '.', - 'decimal' => $commaPos < $periodPos ? '.' : ',', + 'decimal' => $commaPos < $periodPos ? '.' : ',', ]; } elseif ($commaPos === false && $periodPos === false) { return null; @@ -403,7 +418,7 @@ class FloatInt implements SerializableInterface return [ 'thousands' => $isComma ? '.' : ',', - 'decimal' => $isComma ? ',' : '.' + 'decimal' => $isComma ? ',' : '.', ]; } } diff --git a/Stdlib/Base/SmartDateTime.php b/Stdlib/Base/SmartDateTime.php index df0803902..7b7ec08f7 100755 --- a/Stdlib/Base/SmartDateTime.php +++ b/Stdlib/Base/SmartDateTime.php @@ -372,9 +372,9 @@ class SmartDateTime extends \DateTime * * @since 1.0.0 */ - public static function startOfYear(int $month = 1) : SmartDateTime + public static function startOfYear(int $month = 1) : self { - return new SmartDateTime(\date('Y') . '-' . \sprintf('%02d', $month) . '-01'); + return new self(\date('Y') . '-' . \sprintf('%02d', $month) . '-01'); } /** @@ -386,9 +386,9 @@ class SmartDateTime extends \DateTime * * @since 1.0.0 */ - public static function endOfYear(int $month = 1) : SmartDateTime + public static function endOfYear(int $month = 1) : self { - return new SmartDateTime(\date('Y') . '-' . self::calculateMonthIndex(13 - $month, $month) . '-31'); + return new self(\date('Y') . '-' . self::calculateMonthIndex(13 - $month, $month) . '-31'); } /** @@ -398,9 +398,9 @@ class SmartDateTime extends \DateTime * * @since 1.0.0 */ - public static function startOfMonth() : SmartDateTime + public static function startOfMonth() : self { - return new SmartDateTime(\date('Y-m') . '-01'); + return new self(\date('Y-m') . '-01'); } /** @@ -410,9 +410,9 @@ class SmartDateTime extends \DateTime * * @since 1.0.0 */ - public static function endOfMonth() : SmartDateTime + public static function endOfMonth() : self { - return new SmartDateTime(\date('Y-m-t')); + return new self(\date('Y-m-t')); } /** @@ -449,6 +449,15 @@ class SmartDateTime extends \DateTime return \abs(($mod < 0 ? 12 + $mod : $mod) % 12) + 1; } + /** + * Format duration in seconds as d:h:m:s + * + * @param int $duration Duration in seconds + * + * @return string + * + * @since 1.0.0 + */ public static function formatDuration(int $duration) : string { $days = \floor($duration / (24 * 3600)); diff --git a/Uri/HttpUri.php b/Uri/HttpUri.php index 45e53d7f7..ce54e79a3 100755 --- a/Uri/HttpUri.php +++ b/Uri/HttpUri.php @@ -407,7 +407,11 @@ final class HttpUri implements UriInterface if (empty($this->fragment)) { $this->uri .= $toAdd; } else { - $this->uri = \substr_replace($this->uri, $toAdd, \strrpos($this->uri, '#'), 0); + $pos = \strrpos($this->uri, '#'); + + if ($pos !== false) { + $this->uri = \substr_replace($this->uri, $toAdd, $pos, 0); + } } } diff --git a/Utils/Parser/Html/HtmlParser.php b/Utils/Parser/Html/HtmlParser.php index 7de40702a..5f1290105 100644 --- a/Utils/Parser/Html/HtmlParser.php +++ b/Utils/Parser/Html/HtmlParser.php @@ -48,6 +48,10 @@ final class HtmlParser $doc = new \DOMDocument(); $html = \file_get_contents($path); + if ($html === false) { + return ''; + } + $html = \preg_replace( ['~~', '~~'], ['', ''], @@ -63,8 +67,8 @@ final class HtmlParser return empty($node->textContent) ? '' : $node->textContent; } - $content = ''; - $xNode = new \DOMXpath($doc); + $content = ''; + $xNode = new \DOMXpath($doc); $elements = $xNode->query($xpath); if ($elements === false) { diff --git a/Utils/Parser/Markdown/Markdown.php b/Utils/Parser/Markdown/Markdown.php index 245db4a54..155225193 100755 --- a/Utils/Parser/Markdown/Markdown.php +++ b/Utils/Parser/Markdown/Markdown.php @@ -5,9 +5,9 @@ * PHP Version 8.1 * * @package phpOMS\Utils\Parser\Markdown - * @license Original & extra license Emanuil Rusev, erusev.com (MIT) - * @license Extended license Benjamin Hoegh (MIT) - * @license Extreme license doowzs (MIT) + * @copyright Original & extra license Emanuil Rusev, erusev.com (MIT) + * @copyright Extended license Benjamin Hoegh (MIT) + * @copyright Extreme license doowzs (MIT) * @license This version: OMS License 2.0 * @version 1.0.0 * @link https://jingga.app @@ -22,9 +22,9 @@ use phpOMS\Uri\UriFactory; * Markdown parser class. * * @package phpOMS\Utils\Parser\Markdown - * @license Original & extra license Emanuil Rusev, erusev.com (MIT) - * @license Extended license Benjamin Hoegh (MIT) - * @license Extreme license doowzs (MIT) + * @copyright Original & extra license Emanuil Rusev, erusev.com (MIT) + * @copyright Extended license Benjamin Hoegh (MIT) + * @copyright Extreme license doowzs (MIT) * @license This version: OMS License 2.0 * @link https://jingga.app * @see https://github.com/erusev/parsedown @@ -336,7 +336,7 @@ class Markdown /** * TOC array after parsing headers * - * @var array{text:string, id:string, level:string} + * @var array{}|array{text:string, id:string, level:string} * @since 1.0.0 */ protected $contentsListArray = []; @@ -443,7 +443,7 @@ class Markdown return self::$instances[$name]; } - $instance = new static(); + $instance = new self(); self::$instances[$name] = $instance; @@ -594,7 +594,7 @@ class Markdown $html = \trim($html, "\n"); // Merge consecutive dl elements - $html = \preg_replace('/<\/dl>\s+
\s+/', '', $html); + $html = \preg_replace('/<\/dl>\s+
\s+/', '', $html) ?? ''; // Add footnotes if (isset($this->definitionData['Footnote'])) { @@ -651,7 +651,9 @@ class Markdown public function contentsList($typeReturn = 'html') : string { if (\strtolower($typeReturn) === 'json') { - return \json_encode($this->contentsListArray); + $json = \json_encode($this->contentsListArray); + + return $json === false ? '' : $json; } $result = ''; @@ -878,6 +880,7 @@ class Markdown return null; } + $matches = []; if (($excerpt['text'][1] === '/' && \preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $excerpt['text'], $matches)) || ($excerpt['text'][1] === '!' && \preg_match('/^/s', $excerpt['text'], $matches)) || ($excerpt['text'][1] !== ' ' && \preg_match('/^<\w[\w-]*+(?:[ ]*+' . $this->regexHtmlAttribute . ')*+[ ]*+\/?>/s', $excerpt['text'], $matches)) @@ -1332,8 +1335,11 @@ class Markdown */ protected function inlineEmbedding(array $excerpt) : ?array { + $video = false; + $audio = false; + if (!($this->options['embedding'] ?? false) - || !(\str_starts_with($excerpt['text'], '[video') || \str_starts_with($excerpt['text'], '[audio')) + || (!\str_starts_with($excerpt['text'], '[video') && !\str_starts_with($excerpt['text'], '[audio')) || (!($video = (\preg_match('/\[video.*src="([^"]*)".*\]/', $excerpt['text'], $matches) === 1)) && !($audio = (\preg_match('/\[audio.*src="([^"]*)".*\]/', $excerpt['text'], $matches) === 1))) ) { @@ -2009,14 +2015,14 @@ class Markdown /** * Handle block list * - * @param array{body:string, indent:int, text:string} $line Line data - * @param null|array $block Current block + * @param array{body:string, indent:int, text:string} $line Line data + * @param null|array $current Current block * * @return null|array * * @since 1.0.0 */ - protected function blockList(array $line, ?array $block = null) : ?array + protected function blockList(array $line, ?array $current = null) : ?array { if (!($this->options['lists'] ?? true)) { return null; @@ -2039,6 +2045,17 @@ class Markdown } $markerWithoutWhitespace = \strstr($matches[1], ' ', true); + if ($markerWithoutWhitespace === false) { + $markerWithoutWhitespace = $matches[1]; + } + + if ($name === 'ul') { + $markerWithoutWhitespace = \substr($markerWithoutWhitespace, -1); + + if ($markerWithoutWhitespace === false) { + $markerWithoutWhitespace = $matches[1]; + } + } $block = [ 'indent' => $line['indent'], @@ -2046,7 +2063,7 @@ class Markdown 'data' => [ 'type' => $name, 'marker' => $matches[1], - 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : \substr($markerWithoutWhitespace, -1)), + 'markerType' => $markerWithoutWhitespace, ], 'element' => [ 'name' => $name, @@ -2057,12 +2074,17 @@ class Markdown $block['data']['markerTypeRegex'] = \preg_quote($block['data']['markerType'], '/'); if ($name === 'ol') { - $listStart = \ltrim(\strstr($matches[1], $block['data']['markerType'], true), '0') ?: '0'; + $tmp = \strstr($matches[1], $block['data']['markerType'], true); + if ($tmp === false) { + $tmp = $matches[1]; + } + + $listStart = \ltrim($tmp, '0') ?: '0'; if ($listStart !== '1') { - if (isset($currentBlock) - && $currentBlock['type'] === 'Paragraph' - && !isset($currentBlock['interrupted']) + if (isset($current) + && $current['type'] === 'Paragraph' + && !isset($current['interrupted']) ) { return null; } @@ -2175,6 +2197,7 @@ class Markdown } // Get the text of the heading + $text = null; if (isset($block['element']['handler']['argument'])) { $text = $block['element']['handler']['argument']; } @@ -2561,7 +2584,7 @@ class Markdown return null; } - $language = \trim(\preg_replace('/^`{3}([^\s]+)(.+)?/s', '$1', $line['text'])); + $language = \trim(\preg_replace('/^`{3}([^\s]+)(.+)?/s', '$1', $line['text']) ?? ''); if (!($this->options['diagrams'] ?? true) || !\in_array($language, ['mermaid', 'chart']) @@ -2621,7 +2644,6 @@ class Markdown ]; } - return null; } @@ -2650,7 +2672,7 @@ class Markdown return null; } - $summary = \trim(\preg_replace('/^\?{3}(.+)?/s', '$1', $line['text'])); + $summary = \trim(\preg_replace('/^\?{3}(.+)?/s', '$1', $line['text']) ?? ''); $infostring = \trim(\substr($line['text'], $openerLength), "\t "); if (\strpos($infostring, '?') !== false) { @@ -2928,6 +2950,10 @@ class Markdown $attributes = \preg_split('/[ ]+/', $attribute, - 1, \PREG_SPLIT_NO_EMPTY); $classes = []; + if ($attributes === false) { + return []; + } + foreach ($attributes as $attribute) { if ($attribute[0] === '#') { $data['id'] = \substr($attribute, 1); @@ -3083,10 +3109,10 @@ class Markdown // Replace non-alphanumeric characters with our delimiter $optionDelimiter = $this->options['toc']['delimiter'] ?? '-'; - $str = \preg_replace('/[^\p{L}\p{Nd}]+/u', $optionDelimiter, $str); + $str = \preg_replace('/[^\p{L}\p{Nd}]+/u', $optionDelimiter, $str) ?? ''; // Remove duplicate delimiters - $str = \preg_replace('/(' . \preg_quote($optionDelimiter, '/') . '){2,}/', '$1', $str); + $str = \preg_replace('/(' . \preg_quote($optionDelimiter, '/') . '){2,}/', '$1', $str) ?? ''; // Truncate slug to max. characters $optionLimit = $this->options['toc']['limit'] ?? \mb_strlen($str, 'UTF-8'); @@ -3164,7 +3190,7 @@ class Markdown } $newStr .= '-' . $count; - } while(isset($this->anchorDuplicates[$newStr])); + } while (isset($this->anchorDuplicates[$newStr])); $this->anchorDuplicates[$newStr] = 0; @@ -3186,7 +3212,7 @@ class Markdown if (!empty($this->options['headings']['blacklist']) && \is_array($this->options['headings']['blacklist'])) { foreach ($this->options['headings']['blacklist'] as $v) { - $this->anchorDuplicates[$v] = 0; + $this->anchorDuplicates[(string) $v] = 0; } } @@ -3608,7 +3634,7 @@ class Markdown ], ]; - \uasort($this->definitionData['Footnote'], 'self::sortFootnotes'); + \uasort($this->definitionData['Footnote'], ['self', 'sortFootnotes']); foreach ($this->definitionData['Footnote'] as $definitionId => $definitionData) { if (!isset($definitionData['number'])) { @@ -3703,8 +3729,18 @@ class Markdown // http://stackoverflow.com/q/4879946/200145 $dom->loadHTML($elementMarkup); - $dom->removeChild($dom->doctype); - $dom->replaceChild($dom->firstChild->firstChild->firstChild, $dom->firstChild); + + if ($dom->documentElement === null) { + return ''; + } + + if ($dom->doctype !== null) { + $dom->removeChild($dom->doctype); + } + + if ($dom->firstChild !== null && $dom->firstChild->firstChild?->firstChild !== null) { + $dom->replaceChild($dom->firstChild->firstChild->firstChild, $dom->firstChild); + } $elementText = ''; @@ -3719,6 +3755,10 @@ class Markdown } else { foreach ($dom->documentElement->childNodes as $node) { $nodeMarkup = $dom->saveHTML($node); + if ($nodeMarkup === false) { + $nodeMarkup = ''; + } + $elementText .= $node instanceof \DOMElement && !\in_array($node->nodeName, $this->textLevelElements) ? $this->processTag($nodeMarkup) : $nodeMarkup; @@ -3729,6 +3769,9 @@ class Markdown $dom->documentElement->nodeValue = 'placeholder\x1A'; $markup = $dom->saveHTML($dom->documentElement); + if ($markup === false) { + return ''; + } return \str_replace('placeholder\x1A', $elementText, $markup); } @@ -4504,7 +4547,7 @@ class Markdown * * @param array $element Element to render * - * @return : string + * @return string * * @since 1.0.0 */ @@ -4534,6 +4577,7 @@ class Markdown } $permitRawHtml = false; + $text = null; if (isset($element['text'])) { $text = $element['text']; diff --git a/Utils/Parser/Spreadsheet/SpreadsheetParser.php b/Utils/Parser/Spreadsheet/SpreadsheetParser.php index 62ae0664d..b85fc0f4c 100755 --- a/Utils/Parser/Spreadsheet/SpreadsheetParser.php +++ b/Utils/Parser/Spreadsheet/SpreadsheetParser.php @@ -82,7 +82,7 @@ final class SpreadsheetParser /** @var \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter $writer */ $writer = IOFactory::createWriter($spreadsheet, 'custom'); - $html = $writer->generateHtmlAll(); + $html = $writer->generateHtmlAll(); $doc = new \DOMDocument(); $html = \preg_replace( diff --git a/Utils/Parser/Xml/XmlParser.php b/Utils/Parser/Xml/XmlParser.php index c5622d114..3c772a652 100644 --- a/Utils/Parser/Xml/XmlParser.php +++ b/Utils/Parser/Xml/XmlParser.php @@ -45,25 +45,38 @@ final class XmlParser */ public static function parseXml(string $path, string $output = 'xml', string $xpath = '') : string { - $doc = new \DOMDocument(); + $doc = new \DOMDocument(); $doc->preserveWhiteSpace = true; - $doc->formatOutput = true; + $doc->formatOutput = true; $xml = \file_get_contents($path); + if ($xml === false || $xml === null) { + return ''; + } + $xml = \preg_replace( ['~~', '~~'], ['', ''], $xml ); - $doc->loadXML($path); - - if (empty($xpath)) { - return $doc->loadXML($xml); + if ($xml === null) { + return ''; } - $content = ''; - $xNode = new \DOMXpath($doc); + $result = $doc->loadXML($xml); + if ($result === false) { + return ''; + } + + if (empty($xpath)) { + $result = $doc->saveHTML(); + + return $result === false ? '' : $result; + } + + $content = ''; + $xNode = new \DOMXpath($doc); $elements = $xNode->query($xpath); if ($elements === false) { diff --git a/Utils/RnG/Number.php b/Utils/RnG/Number.php index 60012d14c..3bc1a7c47 100644 --- a/Utils/RnG/Number.php +++ b/Utils/RnG/Number.php @@ -24,6 +24,16 @@ namespace phpOMS\Utils\RnG; */ final class Number { + /** + * Generate normal distributed random number + * + * @param int $min Min value + * @param int $max Max value + * + * @return int + * + * @since 1.0.0 + */ public static function normalDistributedRand(int $min, int $max) : int { $u1 = \mt_rand(1, 100) / 100; @@ -36,7 +46,17 @@ final class Number } /** + * Generate exponentially distributed random number + * * For values [0; 100] a lambda of around 0.2 is recommended + * + * @param int $min Min value + * @param int $max Max value + * @param float $lambda Lambda + * + * @return int + * + * @since 1.0.0 */ public static function exponentialDistributedRand(int $min, int $max, float $lambda) : int { diff --git a/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php b/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php index 032ed1ab9..ceb645d00 100755 --- a/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php +++ b/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php @@ -79,7 +79,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -91,7 +91,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -114,7 +114,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -126,7 +126,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -149,7 +149,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -161,7 +161,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -184,7 +184,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -196,7 +196,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -211,7 +211,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->update(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -223,7 +223,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -246,7 +246,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -258,7 +258,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -273,7 +273,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->update(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -285,7 +285,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -308,7 +308,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -320,7 +320,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -335,7 +335,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->update(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -347,7 +347,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -374,7 +374,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -386,7 +386,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -426,7 +426,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -438,7 +438,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -478,7 +478,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase $mapper->insert(); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], @@ -490,7 +490,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase ); $builder = new Builder($this->sqlite, true); - $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC); + $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? []; self::assertEquals( [ ['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'], diff --git a/tests/Views/ViewTest.php b/tests/Views/ViewTest.php index 59a6f6d8a..f4bce81ca 100755 --- a/tests/Views/ViewTest.php +++ b/tests/Views/ViewTest.php @@ -22,7 +22,6 @@ use phpOMS\Localization\L11nManager; use phpOMS\Localization\Localization; use phpOMS\Message\Http\HttpRequest; use phpOMS\Message\Http\HttpResponse; -use phpOMS\Uri\HttpUri; use phpOMS\Views\View; use phpOMS\Views\ViewAbstract;