mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-02-11 06:28:40 +00:00
update
This commit is contained in:
parent
4469789af4
commit
018b9ce981
|
|
@ -166,8 +166,8 @@ final class DBSCAN
|
||||||
/**
|
/**
|
||||||
* Find neighbors of a point
|
* Find neighbors of a point
|
||||||
*
|
*
|
||||||
* @param PointInterface $point Base point for potential neighbors
|
* @param PointInterface $point Base point for potential neighbors
|
||||||
* @param float $epsion Max distance to neighbor
|
* @param float $epsilon Max distance to neighbor
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
|
|
@ -210,6 +210,7 @@ final class DBSCAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var float[] $distances */
|
||||||
return $distances;
|
return $distances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,10 +229,7 @@ final class DBSCAN
|
||||||
foreach ($this->clusters as $c => $cluster) {
|
foreach ($this->clusters as $c => $cluster) {
|
||||||
$points = [];
|
$points = [];
|
||||||
foreach ($cluster as $p) {
|
foreach ($cluster as $p) {
|
||||||
$points[] = [
|
$points[] = $p->coordinates;
|
||||||
'x' => \reset($p->coordinates),
|
|
||||||
'y' => \end($p->coordinates),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->convexHulls[$c] = MonotoneChain::createConvexHull($points);
|
$this->convexHulls[$c] = MonotoneChain::createConvexHull($points);
|
||||||
|
|
@ -239,14 +237,7 @@ final class DBSCAN
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->convexHulls as $c => $hull) {
|
foreach ($this->convexHulls as $c => $hull) {
|
||||||
if (Polygon::isPointInPolygon(
|
if (Polygon::isPointInPolygon($point->coordinates, $hull) <= 0) {
|
||||||
[
|
|
||||||
'x' => \reset($point->coordinates),
|
|
||||||
'y' => \end($point->coordinates),
|
|
||||||
],
|
|
||||||
$hull
|
|
||||||
) <= 0
|
|
||||||
) {
|
|
||||||
return $c;
|
return $c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,8 +239,8 @@ final class MeanShift
|
||||||
/**
|
/**
|
||||||
* Find the closest cluster/group of a point
|
* Find the closest cluster/group of a point
|
||||||
*
|
*
|
||||||
* @param PointInterface $point Point to find the cluster for
|
* @param PointInterface $point Point to find the cluster for
|
||||||
* @param PointInterface[] $group Clusters
|
* @param array<PointInterface[]> $groups Clusters
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ namespace phpOMS\Algorithm\Clustering;
|
||||||
/**
|
/**
|
||||||
* Point interface.
|
* Point interface.
|
||||||
*
|
*
|
||||||
* @property int $group Group
|
* @property int $group Group
|
||||||
* @property string $name Name
|
* @property string $name Name
|
||||||
|
* @property array $coordinates Coordinates
|
||||||
*
|
*
|
||||||
* @package phpOMS\Algorithm\Clustering;
|
* @package phpOMS\Algorithm\Clustering;
|
||||||
* @license OMS License 2.0
|
* @license OMS License 2.0
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ final class Apriori
|
||||||
*
|
*
|
||||||
* @param array<array> $sets Sets of a set (e.g. [[1,2,3,4], [1,2], [1]])
|
* @param array<array> $sets Sets of a set (e.g. [[1,2,3,4], [1,2], [1]])
|
||||||
*
|
*
|
||||||
* @return array<array>
|
* @return array
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Jingga
|
||||||
|
*
|
||||||
|
* PHP Version 8.1
|
||||||
|
*
|
||||||
|
* @package phpOMS\Algorithm\Graph
|
||||||
|
* @copyright Dennis Eichhorn
|
||||||
|
* @license OMS License 2.0
|
||||||
|
* @version 1.0.0
|
||||||
|
* @link https://jingga.app
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace phpOMS\Algorithm\Graph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Markov chain
|
||||||
|
*
|
||||||
|
* @package phpOMS\Algorithm\Graph
|
||||||
|
* @license OMS License 2.0
|
||||||
|
* @link https://jingga.app
|
||||||
|
* @since 1.0.0
|
||||||
|
*
|
||||||
|
* @todo Implement
|
||||||
|
*/
|
||||||
|
final class MarkovChain
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -143,8 +143,8 @@ class GeneticOptimization
|
||||||
|
|
||||||
$fitnesses = [];
|
$fitnesses = [];
|
||||||
|
|
||||||
foreach ($population as $parameters) {
|
foreach ($population as $key => $parameters) {
|
||||||
$fitnesses[$population] = ($fitness)($parameters);
|
$fitnesses[$key] = ($fitness)($parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
\asort($fitnesses);
|
\asort($fitnesses);
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class TabuSearch
|
||||||
|
|
||||||
for ($i = 0; $i < $iterations; ++$i) {
|
for ($i = 0; $i < $iterations; ++$i) {
|
||||||
$neighbors = [];
|
$neighbors = [];
|
||||||
for ($i = 0; $i < $tabuListSize; ++$i) {
|
for ($j = 0; $j < $tabuListSize; ++$j) {
|
||||||
$neighbor = ($neighbor)($currentSolution);
|
$neighbor = ($neighbor)($currentSolution);
|
||||||
$neighbors[] = $neighbor;
|
$neighbors[] = $neighbor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ namespace phpOMS\Algorithm\Rating;
|
||||||
* @package phpOMS\Algorithm\Rating
|
* @package phpOMS\Algorithm\Rating
|
||||||
* @license OMS License 2.0
|
* @license OMS License 2.0
|
||||||
* @link https://jingga.app
|
* @link https://jingga.app
|
||||||
* @since 1.0.0
|
|
||||||
* @see https://en.wikipedia.org/wiki/Bradley%E2%80%93Terry_model
|
* @see https://en.wikipedia.org/wiki/Bradley%E2%80%93Terry_model
|
||||||
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
final class BradleyTerry
|
final class BradleyTerry
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ final class Glicko1
|
||||||
*
|
*
|
||||||
* @see calculateC();
|
* @see calculateC();
|
||||||
*
|
*
|
||||||
* @var int
|
* @var float
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public float $DEFAULT_C = 34.6;
|
public float $DEFAULT_C = 34.6;
|
||||||
|
|
@ -127,7 +127,6 @@ final class Glicko1
|
||||||
) : array
|
) : array
|
||||||
{
|
{
|
||||||
// Step 1:
|
// Step 1:
|
||||||
$s = [];
|
|
||||||
$E = [];
|
$E = [];
|
||||||
$gRD = [];
|
$gRD = [];
|
||||||
|
|
||||||
|
|
@ -145,8 +144,8 @@ final class Glicko1
|
||||||
// Step 2:
|
// Step 2:
|
||||||
foreach ($oElo as $id => $e) {
|
foreach ($oElo as $id => $e) {
|
||||||
$gRD_t = 1 / (\sqrt(1 + 3 * self::Q * self::Q * $oRd[$id] * $oRd[$id] / (\M_PI * \M_PI)));
|
$gRD_t = 1 / (\sqrt(1 + 3 * self::Q * self::Q * $oRd[$id] * $oRd[$id] / (\M_PI * \M_PI)));
|
||||||
$gRD[] = $gRD_t;
|
$gRD[$id] = $gRD_t;
|
||||||
$E[] = 1 / (1 + \pow(10, $gRD_t * ($elo - $e) / -400));
|
$E[$id] = 1 / (1 + \pow(10, $gRD_t * ($elo - $e) / -400));
|
||||||
}
|
}
|
||||||
|
|
||||||
$d = 0;
|
$d = 0;
|
||||||
|
|
|
||||||
|
|
@ -123,13 +123,13 @@ final class Glicko2
|
||||||
|
|
||||||
// Step 1:
|
// Step 1:
|
||||||
$g = [];
|
$g = [];
|
||||||
foreach ($oRd as $rd) {
|
foreach ($oRd as $idx => $rd) {
|
||||||
$g[] = 1 / \sqrt(1 + 3 * $rd * $rd / (\M_PI * \M_PI));
|
$g[$idx] = 1 / \sqrt(1 + 3 * $rd * $rd / (\M_PI * \M_PI));
|
||||||
}
|
}
|
||||||
|
|
||||||
$E = [];
|
$E = [];
|
||||||
foreach ($oElo as $idx => $elo) {
|
foreach ($oElo as $idx => $elo) {
|
||||||
$E[] = 1 / (1 + \exp(-$g[$idx] * ($elo - $elo)));
|
$E[$idx] = 1 / (1 + \exp(-$g[$idx] * ($elo - $elo)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$v = 0;
|
$v = 0;
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ final class CreditSafe implements CreditRatingInterface
|
||||||
$response = Rest::request($request);
|
$response = Rest::request($request);
|
||||||
|
|
||||||
return $response->header->status === 200
|
return $response->header->status === 200
|
||||||
? ($response->get('token') ?? '')
|
? ($response->getDataString('token') ?? '')
|
||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ final class CreditSafe implements CreditRatingInterface
|
||||||
|
|
||||||
$response = Rest::request($request);
|
$response = Rest::request($request);
|
||||||
|
|
||||||
return $response->get('orderID') ?? '';
|
return $response->getDataString('orderID') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ namespace phpOMS\Business\Recommendation;
|
||||||
* @package phpOMS\Business\Recommendation
|
* @package phpOMS\Business\Recommendation
|
||||||
* @license OMS License 2.0
|
* @license OMS License 2.0
|
||||||
* @link https://jingga.app
|
* @link https://jingga.app
|
||||||
* @since 1.0.0
|
|
||||||
* @see https://arxiv.org/ftp/arxiv/papers/1205/1205.2618.pdf
|
* @see https://arxiv.org/ftp/arxiv/papers/1205/1205.2618.pdf
|
||||||
|
* @since 1.0.0
|
||||||
*
|
*
|
||||||
* @todo Implement, current implementation probably wrong
|
* @todo Implement, current implementation probably wrong
|
||||||
*/
|
*/
|
||||||
|
|
@ -40,13 +40,15 @@ final class BayesianPersonalizedRanking
|
||||||
// num_factors determines the dimensionality of the latent factor space.
|
// num_factors determines the dimensionality of the latent factor space.
|
||||||
// learning_rate controls the step size for updating the latent factors during optimization.
|
// learning_rate controls the step size for updating the latent factors during optimization.
|
||||||
// regularization prevents overfitting by adding a penalty for large parameter values.
|
// regularization prevents overfitting by adding a penalty for large parameter values.
|
||||||
public function __construct(int $numFactors, float $learningRate, float $regularization) {
|
public function __construct(int $numFactors, float $learningRate, float $regularization)
|
||||||
|
{
|
||||||
$this->numFactors = $numFactors;
|
$this->numFactors = $numFactors;
|
||||||
$this->learningRate = $learningRate;
|
$this->learningRate = $learningRate;
|
||||||
$this->regularization = $regularization;
|
$this->regularization = $regularization;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generateRandomFactors() {
|
private function generateRandomFactors()
|
||||||
|
{
|
||||||
$factors = [];
|
$factors = [];
|
||||||
for ($i = 0; $i < $this->numFactors; ++$i) {
|
for ($i = 0; $i < $this->numFactors; ++$i) {
|
||||||
$factors[$i] = \mt_rand() / \mt_getrandmax();
|
$factors[$i] = \mt_rand() / \mt_getrandmax();
|
||||||
|
|
@ -67,7 +69,8 @@ final class BayesianPersonalizedRanking
|
||||||
return $score;
|
return $score;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateFactors($userId, $posItemId, $negItemId) : void {
|
public function updateFactors($userId, $posItemId, $negItemId) : void
|
||||||
|
{
|
||||||
if (!isset($this->userFactors[$userId])) {
|
if (!isset($this->userFactors[$userId])) {
|
||||||
$this->userFactors[$userId] = $this->generateRandomFactors();
|
$this->userFactors[$userId] = $this->generateRandomFactors();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ final class JWT
|
||||||
/**
|
/**
|
||||||
* Create JWT signature part
|
* Create JWT signature part
|
||||||
*
|
*
|
||||||
* @param string $secret Secret (at least 256 bit)
|
* @param string $secret Secret (at least 256 bit)
|
||||||
* @param array{alg:string, typ:string} $header Header
|
* @param array{alg:string, typ:string} $header Header
|
||||||
* @param array{sub:string, ?uid:string, ?name:string, iat:string} $payload Payload
|
* @param array{sub:string, ?uid:string, ?name:string, iat:string} $payload Payload
|
||||||
*
|
*
|
||||||
* @return string hmac(Header64 . Payload64, secret)
|
* @return string hmac(Header64 . Payload64, secret)
|
||||||
|
|
@ -60,15 +60,15 @@ final class JWT
|
||||||
/**
|
/**
|
||||||
* Create JWT token
|
* Create JWT token
|
||||||
*
|
*
|
||||||
* @param string $secret Secret (at least 256 bit)
|
* @param string $secret Secret (at least 256 bit)
|
||||||
* @param array{alg:string, typ:string} $header Header
|
* @param array{alg:string, typ:string} $header Header
|
||||||
* @param array{sub:string, ?uid:string, ?name:string, iat:string} $payload Payload
|
* @param array{sub:string, ?uid:string, ?name:string, iat:string} $payload Payload
|
||||||
*
|
*
|
||||||
* @return string Header64 . Payload64 . hmac(Header64 . Payload64, secret)
|
* @return string Header64 . Payload64 . hmac(Header64 . Payload64, secret)
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public static function createJWT(string $secret, array $header = [], array $payload = []) : string
|
public static function createJWT(string $secret, array $header, array $payload) : string
|
||||||
{
|
{
|
||||||
$header64 = Base64Url::encode(\json_encode($header));
|
$header64 = Base64Url::encode(\json_encode($header));
|
||||||
$payload64 = Base64Url::encode(\json_encode($payload));
|
$payload64 = Base64Url::encode(\json_encode($payload));
|
||||||
|
|
@ -94,11 +94,7 @@ final class JWT
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return \json_decode(Base64Url::decode($explode[0]), true);
|
||||||
return \json_decode(Base64Url::decode($explode[0]), true);
|
|
||||||
} catch (\Throwable $_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -118,11 +114,7 @@ final class JWT
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return \json_decode(Base64Url::decode($explode[1]), true);
|
||||||
return \json_decode(Base64Url::decode($explode[1]), true);
|
|
||||||
} catch (\Throwable $_) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -171,11 +171,15 @@ final class EventManager implements \Countable
|
||||||
*/
|
*/
|
||||||
public function triggerSimilar(string $group, string $id = '', mixed $data = null) : bool
|
public function triggerSimilar(string $group, string $id = '', mixed $data = null) : bool
|
||||||
{
|
{
|
||||||
|
if (empty($this->callbacks)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$groupIsRegex = \stripos($group, '/') === 0;
|
$groupIsRegex = \stripos($group, '/') === 0;
|
||||||
$idIsRegex = \stripos($id, '/') === 0;
|
$idIsRegex = \stripos($id, '/') === 0;
|
||||||
|
|
||||||
$groups = [];
|
$groups = [];
|
||||||
foreach ($this->groups as $groupName => $value) {
|
foreach ($this->groups as $groupName => $_) {
|
||||||
$groupNameIsRegex = \stripos($groupName, '/') === 0;
|
$groupNameIsRegex = \stripos($groupName, '/') === 0;
|
||||||
|
|
||||||
if ($groupIsRegex) {
|
if ($groupIsRegex) {
|
||||||
|
|
@ -189,8 +193,8 @@ final class EventManager implements \Countable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($groups as $groupName => $groupValues) {
|
foreach ($groups as $groupName => $_) {
|
||||||
foreach ($this->groups[$groupName] as $idName => $value) {
|
foreach ($this->groups[$groupName] as $idName => $_2) {
|
||||||
$idNameIsRegex = \stripos($idName, '/') === 0;
|
$idNameIsRegex = \stripos($idName, '/') === 0;
|
||||||
|
|
||||||
if ($idIsRegex) {
|
if ($idIsRegex) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ trait ISO3166Trait
|
||||||
*/
|
*/
|
||||||
public static function getBy2Code(string $code) : mixed
|
public static function getBy2Code(string $code) : mixed
|
||||||
{
|
{
|
||||||
|
/** @var string $code3 */
|
||||||
$code3 = ISO3166TwoEnum::getName($code);
|
$code3 = ISO3166TwoEnum::getName($code);
|
||||||
|
|
||||||
return self::getByName($code3);
|
return self::getByName($code3);
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ final class Vector extends Matrix
|
||||||
*/
|
*/
|
||||||
public function cosine(self $v) : float
|
public function cosine(self $v) : float
|
||||||
{
|
{
|
||||||
$dotProduct = 0;
|
$dotProduct = 0.0;
|
||||||
for ($i = 0; $i < $this->m; ++$i) {
|
for ($i = 0; $i < $this->m; ++$i) {
|
||||||
$dotProduct += $this->matrix[$i][0] * $v[$i];
|
$dotProduct += $this->matrix[$i][0] * $v[$i];
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +110,7 @@ final class Vector extends Matrix
|
||||||
}
|
}
|
||||||
$magnitude1 = \sqrt($sumOfSquares);
|
$magnitude1 = \sqrt($sumOfSquares);
|
||||||
|
|
||||||
$sumOfSquares = 0;
|
$sumOfSquares = 0.0;
|
||||||
foreach ($v->matrix as $value) {
|
foreach ($v->matrix as $value) {
|
||||||
$sumOfSquares += $value[0] * $value[0];
|
$sumOfSquares += $value[0] * $value[0];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,12 +107,12 @@ final class MetricsND
|
||||||
*/
|
*/
|
||||||
public static function cosine(array $a, array $b) : float
|
public static function cosine(array $a, array $b) : float
|
||||||
{
|
{
|
||||||
if (\count($a) !== \count($b)) {
|
if (($length = \count($a)) !== \count($b)) {
|
||||||
throw new InvalidDimensionException(\count($a) . 'x' . \count($b));
|
throw new InvalidDimensionException(\count($a) . 'x' . \count($b));
|
||||||
}
|
}
|
||||||
|
|
||||||
$dotProduct = 0;
|
$dotProduct = 0;
|
||||||
for ($i = 0; $i < \count($a); ++$i) {
|
for ($i = 0; $i < $length; ++$i) {
|
||||||
$dotProduct += $a[$i] * $b[$i];
|
$dotProduct += $a[$i] * $b[$i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ final class MetricsND
|
||||||
}
|
}
|
||||||
$magnitude2 = \sqrt($sumOfSquares);
|
$magnitude2 = \sqrt($sumOfSquares);
|
||||||
|
|
||||||
if ($magnitude1 === 0 || $magnitude2 === 0) {
|
if ($magnitude1 == 0 || $magnitude2 == 0) {
|
||||||
return \PHP_FLOAT_MAX;
|
return \PHP_FLOAT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,232 @@ abstract class ResponseAbstract implements \JsonSerializable, MessageInterface
|
||||||
/**
|
/**
|
||||||
* Get response by ID.
|
* Get response by ID.
|
||||||
*
|
*
|
||||||
* @param mixed $id Response ID
|
* @param mixed $key Response ID
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public function get(mixed $id) : mixed
|
public function get(mixed $key, string $type = null) : mixed
|
||||||
{
|
{
|
||||||
return $this->data[$id] ?? null;
|
if ($key === null) {
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = \is_string($key) ? \mb_strtolower($key) : $key;
|
||||||
|
if (!isset($this->data[$key])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case null:
|
||||||
|
return $this->data[$key];
|
||||||
|
case 'int':
|
||||||
|
return (int) $this->data[$key];
|
||||||
|
case 'string':
|
||||||
|
return (string) $this->data[$key];
|
||||||
|
case 'float':
|
||||||
|
return (float) $this->data[$key];
|
||||||
|
case 'bool':
|
||||||
|
return (bool) $this->data[$key];
|
||||||
|
case 'DateTime':
|
||||||
|
return new \DateTime((string) $this->data[$key]);
|
||||||
|
default:
|
||||||
|
return $this->data[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataString(string $key) : ?string
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
if (($this->data[$key] ?? '') === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return null|int
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataInt(string $key) : ?int
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
if (($this->data[$key] ?? '') === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return null|float
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataFloat(string $key) : ?float
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
if (($this->data[$key] ?? '') === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return null|bool
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataBool(string $key) : ?bool
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
if (($this->data[$key] ?? '') === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $this->data[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return null|\DateTime
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataDateTime(string $key) : ?\DateTime
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
return empty($this->data[$key] ?? null)
|
||||||
|
? null
|
||||||
|
: new \DateTime((string) $this->data[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataJson(string $key) : array
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
if (($this->data[$key] ?? '') === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = \json_decode($this->data[$key], true); /** @phpstan-ignore-line */
|
||||||
|
|
||||||
|
return \is_array($json) ? $json : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data.
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
* @param string $delim Data delimiter
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getDataList(string $key, string $delim = ',') : array
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
if (($this->data[$key] ?? '') === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @phpstan-ignore-next-line */
|
||||||
|
$list = \explode($delim, $this->data[$key]);
|
||||||
|
|
||||||
|
if ($list === false) {
|
||||||
|
return []; // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($list as $i => $e) {
|
||||||
|
$list[$i] = \trim($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data based on wildcard.
|
||||||
|
*
|
||||||
|
* @param string $regex Regex data key
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getLike(string $regex) : array
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
foreach ($this->data as $key => $value) {
|
||||||
|
if (\preg_match('/' . $regex . '/', (string) $key) === 1) {
|
||||||
|
$data[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if has data.
|
||||||
|
*
|
||||||
|
* The following empty values are considered as not set (null, '', 0)
|
||||||
|
*
|
||||||
|
* @param string $key Data key
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function hasData(string $key) : bool
|
||||||
|
{
|
||||||
|
$key = \mb_strtolower($key);
|
||||||
|
|
||||||
|
return isset($this->data[$key])
|
||||||
|
&& $this->data[$key] !== ''
|
||||||
|
&& $this->data[$key] !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -697,6 +697,8 @@ abstract class ModuleAbstract
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
|
* @todo find a way to offload this to the cli in a different process (same for other similar functions)
|
||||||
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
protected function createModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void
|
protected function createModel(int $account, mixed $obj, string | \Closure $mapper, string $trigger, string $ip) : void
|
||||||
|
|
@ -712,17 +714,18 @@ abstract class ModuleAbstract
|
||||||
$mapper();
|
$mapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '',
|
$data = [
|
||||||
[
|
$account,
|
||||||
$account,
|
null, $obj,
|
||||||
null, $obj,
|
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
||||||
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
static::NAME,
|
||||||
static::NAME,
|
(string) $id,
|
||||||
(string) $id,
|
null,
|
||||||
null,
|
$ip,
|
||||||
$ip,
|
];
|
||||||
]
|
|
||||||
);
|
$this->app->moduleManager->get('Auditor', 'Api')->eventLogCreate(...$data);
|
||||||
|
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -756,17 +759,18 @@ abstract class ModuleAbstract
|
||||||
$mapper();
|
$mapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '',
|
$data = [
|
||||||
[
|
$account,
|
||||||
$account,
|
null, $obj,
|
||||||
null, $obj,
|
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
||||||
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
static::NAME,
|
||||||
static::NAME,
|
(string) $id,
|
||||||
(string) $id,
|
null,
|
||||||
null,
|
$ip,
|
||||||
$ip,
|
];
|
||||||
]
|
|
||||||
);
|
$this->app->moduleManager->get('Auditor', 'Api')->eventLogCreate(...$data);
|
||||||
|
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -801,17 +805,18 @@ abstract class ModuleAbstract
|
||||||
$mapper();
|
$mapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '',
|
$data = [
|
||||||
[
|
$account,
|
||||||
$account,
|
$old, $new,
|
||||||
$old, $new,
|
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
||||||
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
static::NAME,
|
||||||
static::NAME,
|
(string) $id,
|
||||||
(string) $id,
|
null,
|
||||||
null,
|
$ip,
|
||||||
$ip,
|
];
|
||||||
]
|
|
||||||
);
|
$this->app->moduleManager->get('Auditor', 'Api')->eventLogUpdate(...$data);
|
||||||
|
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -844,17 +849,18 @@ abstract class ModuleAbstract
|
||||||
$mapper();
|
$mapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '',
|
$data = [
|
||||||
[
|
$account,
|
||||||
$account,
|
$obj, null,
|
||||||
$obj, null,
|
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
||||||
StringUtils::intHash(\is_string($mapper) ? $mapper : \get_class($mapper)), $trigger,
|
static::NAME,
|
||||||
static::NAME,
|
(string) $id,
|
||||||
(string) $id,
|
null,
|
||||||
null,
|
$ip,
|
||||||
$ip,
|
];
|
||||||
]
|
|
||||||
);
|
$this->app->moduleManager->get('Auditor', 'Api')->eventLogDelete(...$data);
|
||||||
|
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -890,17 +896,19 @@ abstract class ModuleAbstract
|
||||||
|
|
||||||
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1);
|
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1);
|
||||||
$mapper::writer()->createRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1);
|
$mapper::writer()->createRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1);
|
||||||
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '',
|
|
||||||
[
|
$data = [
|
||||||
$account,
|
$account,
|
||||||
'', [$rel1 => $rel2],
|
'', [$rel1 => $rel2],
|
||||||
StringUtils::intHash($mapper), $trigger,
|
StringUtils::intHash($mapper), $trigger,
|
||||||
static::NAME,
|
static::NAME,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
$ip,
|
$ip,
|
||||||
]
|
];
|
||||||
);
|
|
||||||
|
$this->app->moduleManager->get('Auditor', 'Api')->eventLogRelationCreate(...$data);
|
||||||
|
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -928,16 +936,18 @@ abstract class ModuleAbstract
|
||||||
|
|
||||||
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1);
|
$this->app->eventManager->triggerSimilar('PRE:Module:' . $trigger, '', $rel1);
|
||||||
$mapper::remover()->deleteRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1);
|
$mapper::remover()->deleteRelationTable($field, \is_array($rel2) ? $rel2 : [$rel2], $rel1);
|
||||||
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '',
|
|
||||||
[
|
$data = [
|
||||||
$account,
|
$account,
|
||||||
[$rel1 => $rel2], '',
|
[$rel1 => $rel2], '',
|
||||||
StringUtils::intHash($mapper), $trigger,
|
StringUtils::intHash($mapper), $trigger,
|
||||||
static::NAME,
|
static::NAME,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
$ip,
|
$ip,
|
||||||
]
|
];
|
||||||
);
|
|
||||||
|
$this->app->moduleManager->get('Auditor', 'Api')->eventLogRelationDelete(...$data);
|
||||||
|
$this->app->eventManager->triggerSimilar('POST:Module:' . $trigger, '', $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -293,8 +293,8 @@ final class FileUtils
|
||||||
public static function makeSafeFileName(string $name) : string
|
public static function makeSafeFileName(string $name) : string
|
||||||
{
|
{
|
||||||
$name = \preg_replace("/[^A-Za-z0-9\-_.]/", '_', $name);
|
$name = \preg_replace("/[^A-Za-z0-9\-_.]/", '_', $name);
|
||||||
$name = \preg_replace("/_+/", '_', $name);
|
$name = \preg_replace("/_+/", '_', $name ?? '');
|
||||||
$name = \trim($name, '_');
|
$name = \trim($name ?? '', '_');
|
||||||
$name = \strtolower($name);
|
$name = \strtolower($name);
|
||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,9 @@ final class ArrayUtils
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return \trim($args[(int) $key + 1], '" ');
|
$value = $args[(int) $key + 1];
|
||||||
|
|
||||||
|
return \is_string($value) ? \trim($value, '" ') : $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ class HtmlFormatter
|
||||||
$dom->preserveWhiteSpace = false;
|
$dom->preserveWhiteSpace = false;
|
||||||
$dom->formatOutput = true;
|
$dom->formatOutput = true;
|
||||||
|
|
||||||
return $dom->saveXML($dom->documentElement);
|
$formatted = $dom->saveXML($dom->documentElement);
|
||||||
|
|
||||||
|
return $formatted === false ? '' : $formatted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -312,13 +312,17 @@ final class ImageUtils
|
||||||
$color1Avg = self::getAverageColor($src1, $i, $j, $imageDim2[0], $imageDim2[1], $diffArea);
|
$color1Avg = self::getAverageColor($src1, $i, $j, $imageDim2[0], $imageDim2[1], $diffArea);
|
||||||
$color2Avg = self::getAverageColor($src2, $i, $j, $newDim[0], $newDim[1], $diffArea);
|
$color2Avg = self::getAverageColor($src2, $i, $j, $newDim[0], $newDim[1], $diffArea);
|
||||||
|
|
||||||
$color1 = \imagecolorat($src1, $i, $j);
|
//$color1 = \imagecolorat($src1, $i, $j);
|
||||||
$color2 = \imagecolorat($src2, $i, $j);
|
$color2 = \imagecolorat($src2, $i, $j);
|
||||||
|
|
||||||
if (\abs($color1Avg - $color2Avg) / $color1Avg > 0.05 && $color1Avg > 0 && $color2Avg > 0) {
|
if (\abs($color1Avg - $color2Avg) / $color1Avg > 0.05 && $color1Avg > 0 && $color2Avg > 0) {
|
||||||
++$difference;
|
++$difference;
|
||||||
|
|
||||||
if ($diff === 0) {
|
if ($diff === 0) {
|
||||||
|
if ($color2 === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/** @var \GdImage $dst */
|
/** @var \GdImage $dst */
|
||||||
\imagesetpixel($dst, $i, $j, $color2);
|
\imagesetpixel($dst, $i, $j, $color2);
|
||||||
} elseif ($diff === 1) {
|
} elseif ($diff === 1) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user