Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test implementation of collection objects #191

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions src/Models/AbstractCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

namespace CTApi\Models;


use ArrayAccess;
use ArrayObject;
use Countable;
use IteratorAggregate;
use Traversable;

abstract class AbstractCollection implements IteratorAggregate, ArrayAccess, Countable
{
private ArrayObject $arrayObject;

public function __construct(array $array = [])
{
foreach($array as $value){
$this->validateValue($value);
}
$this->arrayObject = new ArrayObject($array);
}

protected abstract function getClassType(): string;

protected abstract function createInstance(array $data): AbstractCollection;

private function validateValue(mixed $value): void
{
$classType = $this->getClassType();
if(!is_a($value, $classType)){
$valueType = is_object($value) ? get_class($value) : gettype($value);
throw new \InvalidArgumentException("Value from type " . $valueType . " is not assignable to Collection from type " . get_class($this));
}
}

/**
* Alias for append.
* @param object $value
* @return void
*/
public function push(object $value): void
{
$this->append($value);
}
public function append(object $value): void
{
$this->validateValue($value);
$this->arrayObject[] = $value;
}

public function first(): ?object
{
$iterator = $this->arrayObject->getIterator();
return $iterator->current();
}

public function filter(callable $callback, int $mode = 0): self
{
$filtered = array_filter((array) $this->arrayObject, $callback, $mode);
return $this->createInstance($filtered);
}

public function map(callable $callback): self
{
$filtered = array_map($callback, (array) $this->arrayObject);
return $this->createInstance($filtered);
}

public function count(): int
{
return $this->arrayObject->count();
}

/**
* Sort the entries by value
* @param int $flags
* @return bool
*/
public function asort(int $flags = SORT_REGULAR): bool
{
return $this->arrayObject->asort($flags);

Check failure on line 82 in src/Models/AbstractCollection.php

View workflow job for this annotation

GitHub Actions / build

Method CTApi\Models\AbstractCollection::asort() should return bool but returns void.

Check failure on line 82 in src/Models/AbstractCollection.php

View workflow job for this annotation

GitHub Actions / build

Result of method ArrayObject<(int|string),mixed>::asort() (void) is used.
}

/**
* Sort the entries by key
* @param int $flags
* @return bool
*/
public function ksort(int $flags = SORT_REGULAR): bool
{
return $this->arrayObject->ksort($flags);

Check failure on line 92 in src/Models/AbstractCollection.php

View workflow job for this annotation

GitHub Actions / build

Method CTApi\Models\AbstractCollection::ksort() should return bool but returns void.

Check failure on line 92 in src/Models/AbstractCollection.php

View workflow job for this annotation

GitHub Actions / build

Result of method ArrayObject<(int|string),mixed>::ksort() (void) is used.
}

/**
* Sort the entries with a user-defined comparison function and maintain key association
* @param callable $callback
* @return bool
*/
public function uasort(callable $callback): bool
{
return $this->arrayObject->uasort($callback);

Check failure on line 102 in src/Models/AbstractCollection.php

View workflow job for this annotation

GitHub Actions / build

Method CTApi\Models\AbstractCollection::uasort() should return bool but returns void.

Check failure on line 102 in src/Models/AbstractCollection.php

View workflow job for this annotation

GitHub Actions / build

Result of method ArrayObject<(int|string),mixed>::uasort() (void) is used.
}

public function getIterator(): Traversable
{
return $this->arrayObject->getIterator();
}

public function offsetExists(mixed $offset): bool
{
return $this->arrayObject->offsetExists($offset);
}

public function offsetGet(mixed $offset): mixed
{
return $this->arrayObject->offsetGet($offset);
}

public function offsetSet(mixed $offset, mixed $value): void
{
$this->validateValue($value);
$this->arrayObject->offsetSet($offset, $value);
}

public function offsetUnset(mixed $offset): void
{
$this->arrayObject->offsetUnset($offset);
$this->filterNullableEntries();
}

private function filterNullableEntries(): void
{
$withoutNullable = array_filter($this->arrayObject->getArrayCopy(), function($element){
return isset($element);
});
$this->arrayObject->exchangeArray(array_values($withoutNullable));
}
}
13 changes: 13 additions & 0 deletions src/Models/Groups/Group/GroupTypeCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace CTApi\Models\Groups\Group;

use CTApi\Models\AbstractCollection;

class GroupTypeCollection extends AbstractCollection

Check failure on line 7 in src/Models/Groups/Group/GroupTypeCollection.php

View workflow job for this annotation

GitHub Actions / build

Non-abstract class CTApi\Models\Groups\Group\GroupTypeCollection contains abstract method createInstance() from class CTApi\Models\AbstractCollection.
{
protected function getClassType(): string
{
return GroupType::class;
}
}
4 changes: 2 additions & 2 deletions src/Models/Groups/Group/GroupTypeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

class GroupTypeRequest
{
public static function all(): array
public static function all(): GroupTypeCollection
{
return (new GroupTypeRequestBuilder())->all();
return new GroupTypeCollection((new GroupTypeRequestBuilder())->all());
}

public static function where(string $key, $value): GroupTypeRequestBuilder
Expand Down
26 changes: 26 additions & 0 deletions src/Models/Groups/GroupMember/GroupMemberCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace CTApi\Models\Groups\GroupMember;

use CTApi\Models\AbstractCollection;
use CTApi\Models\Groups\Person\PersonCollection;
use CTApi\Models\Groups\Person\PersonRequest;

class GroupMemberCollection extends AbstractCollection

Check failure on line 9 in src/Models/Groups/GroupMember/GroupMemberCollection.php

View workflow job for this annotation

GitHub Actions / build

Non-abstract class CTApi\Models\Groups\GroupMember\GroupMemberCollection contains abstract method createInstance() from class CTApi\Models\AbstractCollection.
{

protected function getClassType(): string
{
return GroupMember::class;
}

public function requestPersons(): PersonCollection
{
$ids = array_map(function(GroupMember $groupMember){
return $groupMember->getPersonId();
}, $this);

Check failure on line 21 in src/Models/Groups/GroupMember/GroupMemberCollection.php

View workflow job for this annotation

GitHub Actions / build

Parameter #2 $array of function array_map expects array, $this(CTApi\Models\Groups\GroupMember\GroupMemberCollection) given.

return PersonRequest::where('ids', $ids)->get();

Check failure on line 23 in src/Models/Groups/GroupMember/GroupMemberCollection.php

View workflow job for this annotation

GitHub Actions / build

Method CTApi\Models\Groups\GroupMember\GroupMemberCollection::requestPersons() should return CTApi\Models\Groups\Person\PersonCollection but returns array.
}

}
13 changes: 13 additions & 0 deletions src/Models/Groups/Person/PersonCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace CTApi\Models\Groups\Person;

use CTApi\Models\AbstractCollection;

class PersonCollection extends AbstractCollection
{
protected function getClassType(): string
{
return Person::class;
}
}
17 changes: 17 additions & 0 deletions tests/Unit/Models/Collection/Car.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace CTApi\Test\Unit\Models\Collection;

class Car
{
public function __construct(
public string $brand
)
{
}

public static function fromBrand(string $brand): Car
{
return new Car($brand);
}
}
18 changes: 18 additions & 0 deletions tests/Unit/Models/Collection/CarCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace CTApi\Test\Unit\Models\Collection;

use CTApi\Models\AbstractCollection;

class CarCollection extends AbstractCollection
{
protected function getClassType(): string
{
return Car::class;
}

protected function createInstance(array $data): CarCollection
{
return new CarCollection($data);
}
}
136 changes: 136 additions & 0 deletions tests/Unit/Models/Collection/CollectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

namespace CTApi\Test\Unit\Models\Collection;

use CTApi\Models\Groups\Group\Group;
use CTApi\Models\Groups\Person\Person;
use CTApi\Models\PersonCustomCollection;
use PHPUnit\Framework\TestCase;

class CollectionTest extends TestCase
{

public function testAddCollection()
{
$carCollection = new CarCollection();
$carCollection[] = new Car("mercedes");
$carCollection->append(new Car("bmw"));
$carCollection[] = new Car("daimler");

$this->assertEquals(3, sizeof($carCollection));
}

public function testAddCollection_TypeCheck()
{
$this->expectException(\InvalidArgumentException::class);
$carCollection = new CarCollection();
$carCollection[] = new Car("mercedes");
$carCollection[] = "awidon";
}

public function testCreateCollection()
{
$car1 = new Car("mercedes");
$car2 = new Car("bmw");
$carCollection = new CarCollection([$car1, $car2]);
$this->assertEquals(2, sizeof($carCollection));
}

public function testCreateCollection_TypeCheck()
{
$this->expectException(\InvalidArgumentException::class);
$carCollection = new CarCollection(["test"]);
}

public function testGetSpecificElement()
{
$car1 = new Car("mercedes");
$car2 = new Car("bmw");
$carCollection = new CarCollection([$car1, $car2]);

$car = $carCollection->offsetGet(1);
$this->assertEquals($car->brand, "bmw");

$car = $carCollection[0];
$this->assertEquals($car->brand, "mercedes");
}

public function testRemoveElement()
{
$car1 = new Car("mercedes");
$car2 = new Car("bmw");
$car3 = new Car("daimler");
$carCollection = new CarCollection([$car1, $car2, $car3]);

$carCollection->offsetUnset(1);
$this->assertEquals(2, sizeof($carCollection));
}

public function testRemoveElementInLoop()
{
$car1 = new Car("mercedes");
$car2 = new Car("bmw");
$car3 = new Car("daimler");

$carCollection = new CarCollection([$car1, $car2, $car3]);

$numberOfIterations = 0;
foreach($carCollection as $car)
{
echo "\n". $car->brand;
if($car->brand === "bmw"){
$carCollection->offsetUnset(1);
}
$numberOfIterations++;
}
$this->assertEquals(3, $numberOfIterations);
}

public function testGetFirstElement()
{
$car1 = new Car("mercedes");
$car2 = new Car("bmw");
$car3 = new Car("daimler");

$carCollection = new CarCollection([$car1, $car2, $car3]);

foreach($carCollection as $carIterator){
$car = $carCollection->first();
$this->assertEquals("mercedes", $car->brand);
}
}

public function testGetFirstElement_Empty()
{
$carCollection = new CarCollection();
$this->assertNull($carCollection->first());
}

public function testGetFirstElement_FirstUnset()
{
$carCollection = new CarCollection([Car::fromBrand("mercedes"), Car::fromBrand("audi")]);
$this->assertNotNull($carCollection->first());
$this->assertEquals("mercedes", $carCollection->first()->brand);

$carCollection->offsetUnset(0);
$this->assertNotNull($carCollection->first());
$this->assertEquals("audi", $carCollection->first()->brand);
}

public function testFilter()
{
$car1 = new Car("mercedes");
$car2 = new Car("bmw");
$car3 = new Car("daimler");

$carCollection = new CarCollection([$car1, $car2, $car3]);


$carCollectionFiltered = $carCollection->filter(function($test){
return $test->brand === "bmw";
});

$this->assertEquals(sizeof($carCollectionFiltered), 1);
}

}
Loading