mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-02-08 13:28:39 +00:00
fix bugs and start impl. additional functions
This commit is contained in:
parent
e2f6061fa7
commit
522db1d462
|
|
@ -416,11 +416,11 @@ class DataMapperAbstract implements DataMapperInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($condValue['value'] !== null) {
|
if ($condValue['value'] !== null) {
|
||||||
$where1->andWhere(static::$table . '_' . $searchDepth . '.' . $column, $condValue['comparison'], $condValue['value']);
|
$where1->andWhere(static::$table . '_d' . $searchDepth . '.' . $column, $condValue['comparison'], $condValue['value']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($condValue['orderBy'] !== null) {
|
if ($condValue['orderBy'] !== null) {
|
||||||
$where1->orderBy(static::$table . '_' . $searchDepth . '.' . static::getColumnByMember($condValue['orderBy']), $condValue['sortOrder']);
|
$where1->orderBy(static::$table . '_d' . $searchDepth . '.' . static::getColumnByMember($condValue['orderBy']), $condValue['sortOrder']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($condValue['limit'] !== null) {
|
if ($condValue['limit'] !== null) {
|
||||||
|
|
@ -433,7 +433,7 @@ class DataMapperAbstract implements DataMapperInterface
|
||||||
$hasAutocompletes = false;
|
$hasAutocompletes = false;
|
||||||
foreach (static::$columns as $col) {
|
foreach (static::$columns as $col) {
|
||||||
if (isset($col['autocomplete']) && $col['autocomplete']) {
|
if (isset($col['autocomplete']) && $col['autocomplete']) {
|
||||||
$where2->where(static::$table . '_' . $searchDepth . '.' . $col['name'], 'LIKE', '%' . $search . '%', 'OR');
|
$where2->where(static::$table . '_d' . $searchDepth . '.' . $col['name'], 'LIKE', '%' . $search . '%', 'OR');
|
||||||
$hasAutocompletes = true;
|
$hasAutocompletes = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace phpOMS\Message;
|
namespace phpOMS\Message;
|
||||||
|
|
||||||
|
use phpOMS\Localization\ISO639x1Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response abstract class.
|
* Response abstract class.
|
||||||
*
|
*
|
||||||
|
|
@ -100,6 +102,10 @@ abstract class ResponseAbstract implements \JsonSerializable, MessageInterface
|
||||||
*/
|
*/
|
||||||
public function getLanguage() : string
|
public function getLanguage() : string
|
||||||
{
|
{
|
||||||
|
if (!isset($this->header)) {
|
||||||
|
return ISO639x1Enum::_EN;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->header->l11n->getLanguage();
|
return $this->header->l11n->getLanguage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ class Edge
|
||||||
* @var float
|
* @var float
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
private float $weight = 0.0;
|
private float $weight = 1.0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
|
@ -70,7 +70,7 @@ class Edge
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public function __construct(Node $node1, Node $node2, float $weight = 0.0, bool $isDirected = false)
|
public function __construct(Node $node1, Node $node2, float $weight = 1.0, bool $isDirected = false)
|
||||||
{
|
{
|
||||||
$this->node1 = $node1;
|
$this->node1 = $node1;
|
||||||
$this->node2 = $node2;
|
$this->node2 = $node2;
|
||||||
|
|
|
||||||
|
|
@ -21,29 +21,6 @@ namespace phpOMS\Stdlib\Graph;
|
||||||
* @license OMS License 1.0
|
* @license OMS License 1.0
|
||||||
* @link https://orange-management.org
|
* @link https://orange-management.org
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*
|
|
||||||
* @todo Orange-Management/phpOMS#10
|
|
||||||
* * Count all paths between 2 nodes
|
|
||||||
* * Return all paths between 2 nodes
|
|
||||||
* * Find cycles using graph coloring
|
|
||||||
* * Find a negative cycle
|
|
||||||
* * Find cycles with n length
|
|
||||||
* * Find cycles with odd length
|
|
||||||
* * Find shortest path between 2 nodes
|
|
||||||
* * Find longest path between 2 nodes
|
|
||||||
* * Find islands
|
|
||||||
* * Find all unreachable nodes
|
|
||||||
* * Check if strongly connected
|
|
||||||
* * Find longest path between 2 nodes
|
|
||||||
* * Find longest path
|
|
||||||
* * Get the girth
|
|
||||||
* * Get the circuit rank
|
|
||||||
* * Get the node connectivity
|
|
||||||
* * Get the edge connectivity
|
|
||||||
* * Is the graph connected
|
|
||||||
* * Get the unconnected nodes as their own graph
|
|
||||||
* * Check if bipartite
|
|
||||||
* * Check if triangle free
|
|
||||||
*/
|
*/
|
||||||
class Graph
|
class Graph
|
||||||
{
|
{
|
||||||
|
|
@ -511,15 +488,79 @@ class Graph
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform depth first traversal.
|
* Perform depth first traversal
|
||||||
|
*
|
||||||
|
* @param int|string|Node $node1 Graph node
|
||||||
|
* @param int|string|Node $node2 Graph node
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public function depthFirstTraversal() : array
|
private function depthFirstTraversal(
|
||||||
|
int | string | Node $node1,
|
||||||
|
int | string | Node $node2 = null,
|
||||||
|
array &$visited,
|
||||||
|
array &$path,
|
||||||
|
array &$paths
|
||||||
|
) : array
|
||||||
{
|
{
|
||||||
return [];
|
$visited[$node1->getId()] = true;
|
||||||
|
|
||||||
|
if ($node1->isEquals($node2)) {
|
||||||
|
$paths[] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
$neighbors = $node1->getNeighbors();
|
||||||
|
foreach ($neighbors as $neighbor) {
|
||||||
|
if (!isset($visited[$neighbor->getId()]) || !$visited[$neighbor->getId()]) {
|
||||||
|
$path[] = $neighbor;
|
||||||
|
$this->depthFirstTraversal($neighbor, $node2, $visited, $path);
|
||||||
|
\array_pop($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$visited[$node1->getId()] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all reachable nodes with depth first traversal (iterative)
|
||||||
|
*
|
||||||
|
* @param int|string|Node $node1 Graph node
|
||||||
|
*
|
||||||
|
* @return Node[]
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function findAllReachableNodesDFS(int | string | Node $node1) : array
|
||||||
|
{
|
||||||
|
$nodes = [];
|
||||||
|
|
||||||
|
if (!($node1 instanceof Node)) {
|
||||||
|
$node1 = $this->getNode($node1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$visited = [];
|
||||||
|
$stack = [];
|
||||||
|
$stack[] = $node1;
|
||||||
|
|
||||||
|
while (!empty($stack)) {
|
||||||
|
$cNode = \array_pop($stack);
|
||||||
|
$nodes[] = $cNode;
|
||||||
|
|
||||||
|
if (!isset($visited[$cNode->getId()]) || !$visited[$cNode->getId()]) {
|
||||||
|
$visited[$cNode->getId()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$neighbors = $cNode->getNeighbors();
|
||||||
|
foreach ($neighbors as $neighbor) {
|
||||||
|
if (!isset($visited[$cNode->getId()]) || !$visited[$cNode->getId()]) {
|
||||||
|
$stack[] = $neighbor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -546,6 +587,54 @@ class Graph
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all paths between two nodes
|
||||||
|
*
|
||||||
|
* @param int|string|Node $node1 Graph node
|
||||||
|
* @param int|string|Node $node2 Graph node
|
||||||
|
*
|
||||||
|
* @return array<int, Node[]>
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getAllPathsBetweenNodes(int | string | Node $node1, int | string | Node $node2) : array
|
||||||
|
{
|
||||||
|
if (!($node1 instanceof Node)) {
|
||||||
|
$node1 = $this->getNode($node1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($node2 instanceof Node)) {
|
||||||
|
$node2 = $this->getNode($node2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node1 === null || $node2 === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = [];
|
||||||
|
$paths = [];
|
||||||
|
$visited = [];
|
||||||
|
|
||||||
|
$this->depthFirstTraversal($node1, $node2, $visited, $path, $paths);
|
||||||
|
|
||||||
|
return $paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count possible paths between two nodes.
|
||||||
|
*
|
||||||
|
* @param int|string|Node $node1 Graph node
|
||||||
|
* @param int|string|Node $node2 Graph node
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function countAllPathsBetweenNodes(int | string | Node $node1, int | string | Node $node2) : int
|
||||||
|
{
|
||||||
|
return \count($this->getAllPathsBetweenNodes($node1, $node2));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get longest path between two nodes.
|
* Get longest path between two nodes.
|
||||||
*
|
*
|
||||||
|
|
@ -558,15 +647,48 @@ class Graph
|
||||||
*/
|
*/
|
||||||
public function longestPathBetweenNodes(int | string | Node $node1, int | string | Node $node2) : array
|
public function longestPathBetweenNodes(int | string | Node $node1, int | string | Node $node2) : array
|
||||||
{
|
{
|
||||||
if (!($node1 instanceof Node)) {
|
$paths = $this->getAllPathsBetweenNodes($node1, $node2);
|
||||||
$node1 = $this->getNode($node1);
|
|
||||||
|
if (empty($paths)) {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!($node2 instanceof Node)) {
|
foreach ($paths as $key => $path) {
|
||||||
$node2 = $this->getNode($node2);
|
$edges[$key] = 0;
|
||||||
|
foreach ($path as $node) {
|
||||||
|
$edges[$key] += $node->getEdgeByNeighbor()->getWeight();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
\arsort($edges);
|
||||||
|
|
||||||
|
return $paths[\array_key_first($edges)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get shortest path between two nodes.
|
||||||
|
*
|
||||||
|
* @param int|string|Node $node1 Graph node
|
||||||
|
* @param int|string|Node $node2 Graph node
|
||||||
|
*
|
||||||
|
* @return Node[]
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function shortestPathBetweenNodes(int | string | Node $node1, int | string | Node $node2) : array
|
||||||
|
{
|
||||||
|
$paths = $this->getAllPathsBetweenNodes($node1, $node2);
|
||||||
|
|
||||||
|
foreach ($paths as $key => $path) {
|
||||||
|
$edges[$key] = 0;
|
||||||
|
foreach ($path as $node) {
|
||||||
|
$edges[$key] += $node->getEdgeByNeighbor()->getWeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\asort($edges);
|
||||||
|
|
||||||
|
return $paths[\array_key_first($edges)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -684,21 +806,13 @@ class Graph
|
||||||
*/
|
*/
|
||||||
public function isConnected() : bool
|
public function isConnected() : bool
|
||||||
{
|
{
|
||||||
return true;
|
if (empty($this->nodes)) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
$nodes = $this->findAllReachableNodesDFS(\reset($this->nodes));
|
||||||
* Get unconnected sub graphs
|
|
||||||
*
|
|
||||||
* @return Graph[]
|
|
||||||
*
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public function getUnconnected() : array
|
|
||||||
{
|
|
||||||
// get all unconnected sub graphs
|
|
||||||
|
|
||||||
return [];
|
return \count($nodes) === \count($this->nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,26 @@ class Node
|
||||||
return $this->edges[$key] ?? null;
|
return $this->edges[$key] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get graph edge by neighbor.
|
||||||
|
*
|
||||||
|
* @param Node $node Neighbor node
|
||||||
|
*
|
||||||
|
* @return null|Edge
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getEdgeByNeighbor(self $node) : ?Edge
|
||||||
|
{
|
||||||
|
foreach ($this->edges as $edge) {
|
||||||
|
if ($edge->getNode1()->isEqual($node) || $edge->getNode2()->isEqual($node)) {
|
||||||
|
return $edge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get graph edges
|
* Get graph edges
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ namespace phpOMS\tests\Message;
|
||||||
require_once __DIR__ . '/../Autoloader.php';
|
require_once __DIR__ . '/../Autoloader.php';
|
||||||
|
|
||||||
use phpOMS\Message\ResponseAbstract;
|
use phpOMS\Message\ResponseAbstract;
|
||||||
|
use phpOMS\Localization\ISO639x1Enum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @testdox phpOMS\tests\Message\ResponseAbstractTest: Abstract response
|
* @testdox phpOMS\tests\Message\ResponseAbstractTest: Abstract response
|
||||||
|
|
@ -52,6 +53,7 @@ class ResponseAbstractTest extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
self::assertNull($this->response->get('asdf'));
|
self::assertNull($this->response->get('asdf'));
|
||||||
self::assertEquals('', $this->response->getBody());
|
self::assertEquals('', $this->response->getBody());
|
||||||
|
self::assertTrue(ISO639x1Enum::isValidValue($this->response->getLanguage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class EdgeTest extends \PHPUnit\Framework\TestCase
|
||||||
self::assertEquals([new Node('1'), new Node('2')], $edge->getNodes());
|
self::assertEquals([new Node('1'), new Node('2')], $edge->getNodes());
|
||||||
self::assertTrue($edge->getNode1()->isEqual(new Node('1')));
|
self::assertTrue($edge->getNode1()->isEqual(new Node('1')));
|
||||||
self::assertTrue($edge->getNode2()->isEqual(new Node('2')));
|
self::assertTrue($edge->getNode2()->isEqual(new Node('2')));
|
||||||
self::assertEquals(0.0, $edge->getWeight());
|
self::assertEquals(1.0, $edge->getWeight());
|
||||||
self::assertFalse($edge->isDirected());
|
self::assertFalse($edge->isDirected());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,8 +57,8 @@ class EdgeTest extends \PHPUnit\Framework\TestCase
|
||||||
*/
|
*/
|
||||||
public function testWeightInputOutput() : void
|
public function testWeightInputOutput() : void
|
||||||
{
|
{
|
||||||
$edge = new Edge(new Node('7'), new Node('8'), 1.0, true);
|
$edge = new Edge(new Node('7'), new Node('8'), 2.0, true);
|
||||||
self::assertEquals(1.0, $edge->getWeight());
|
self::assertEquals(2.0, $edge->getWeight());
|
||||||
|
|
||||||
$edge = new Edge(new Node('7'), new Node('8'), 1.0);
|
$edge = new Edge(new Node('7'), new Node('8'), 1.0);
|
||||||
$edge->setWeight(3.0);
|
$edge->setWeight(3.0);
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,8 @@ class GraphTest extends \PHPUnit\Framework\TestCase
|
||||||
self::assertEquals([], $this->graph->getBridges());
|
self::assertEquals([], $this->graph->getBridges());
|
||||||
self::assertEquals([], $this->graph->getFloydWarshallShortestPath());
|
self::assertEquals([], $this->graph->getFloydWarshallShortestPath());
|
||||||
self::assertEquals([], $this->graph->getDijkstraShortestPath());
|
self::assertEquals([], $this->graph->getDijkstraShortestPath());
|
||||||
self::assertEquals([], $this->graph->depthFirstTraversal());
|
|
||||||
self::assertEquals([], $this->graph->breadthFirstTraversal());
|
|
||||||
self::assertEquals([], $this->graph->longestPath());
|
self::assertEquals([], $this->graph->longestPath());
|
||||||
self::assertEquals([], $this->graph->longestPathBetweenNodes('invalid1', 'invalid2'));
|
self::assertEquals([], $this->graph->longestPathBetweenNodes('invalid1', 'invalid2'));
|
||||||
self::assertEquals([], $this->graph->getUnconnected());
|
|
||||||
|
|
||||||
self::assertEquals(0, $this->graph->getCost());
|
self::assertEquals(0, $this->graph->getCost());
|
||||||
self::assertEquals($this->graph, $this->graph->getKruskalMinimalSpanningTree());
|
self::assertEquals($this->graph, $this->graph->getKruskalMinimalSpanningTree());
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
|
||||||
self::assertEquals(\basename(__DIR__ . '/FileUtilsTest.php'), FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_BASENAME));
|
self::assertEquals(\basename(__DIR__ . '/FileUtilsTest.php'), FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_BASENAME));
|
||||||
self::assertEquals('php', FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_EXTENSION));
|
self::assertEquals('php', FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_EXTENSION));
|
||||||
self::assertEquals('FileUtilsTest', FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_FILENAME));
|
self::assertEquals('FileUtilsTest', FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_FILENAME));
|
||||||
|
|
||||||
self::assertEquals(
|
self::assertEquals(
|
||||||
[
|
[
|
||||||
'dirname' => __DIR__,
|
'dirname' => __DIR__,
|
||||||
|
|
@ -108,7 +109,7 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
|
||||||
'extension' => 'php',
|
'extension' => 'php',
|
||||||
'filename' => 'FileUtilsTest',
|
'filename' => 'FileUtilsTest',
|
||||||
],
|
],
|
||||||
FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php', \PATHINFO_FILENAME)
|
FileUtils::mb_pathinfo(__DIR__ . '/FileUtilsTest.php')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user