Skip to content

Entity collections

All results from Small Swoole Entity Manager inherit from EntityCollection class.

You can extend this class in order to implement specific methods for your entities.

The collection has the behaviour of an array but is also an object.

See Small Collection package for all functionalities.

Use it as an array

Collection are iterables and support most of array functionnalities :

<?php
$collection = new Collection(['a', 'b', 'c', 'd', 'e']);

foreach ($collection as $key => $value) {
    echo $value;
}

$result = $collection[3];

Use it as an object

You can set a value for a specific key :

<?php
$collection = new \Small\Collection\Collection\Collection();
$key = 101;
$value = 'test';
$collection->set($key, $value);

And use it :

<?php
echo $collection[$key];

EntityCollection methods

persist

You can perform persist on all entities in collection :

<?php
$collection = $userManager->findBy(['type' => 'customer']);

$collection->map(function (int $key, UserEntity $user) {
    $user->addPoints(rand(1, 10));
});

$collection->persist();

delete

You can perform deletion of all entities of collection from database :

<?php
$userManager->findBy(['type' => 'customer'])
    ->delete()
;

Extending EntityCollection

Extending EntityCollection allow you to create methods specific for a given group of entity.

First create collection :

<?php
    /* File : EntityCollection/UserEntityCollection.php */
    namespace MyApp\EntityCollection;

    use Small\SwooleEntityManager\Entity\EntityCollection;

    class UserEntityCollection extends EntityCollection
    {

        public function getChilds: self
        {

            return $this->filterByCallback(fn($key, $user) => $user->getAge() < 18);

        }

    }

And tag your entity :

<?php
    /* File : Entity/UserEntity.php */
    namespace MyApp\Entity;

    use Small\SwooleEntityManager\Entity\AbstractEntity;
    use Small\SwooleEntityManager\Entity\Attribute\PrimaryKey;
    use Small\SwooleEntityManager\Entity\Attribute\Field;
    use Small\SwooleEntityManager\Entity\Attribute\Collection;
    use Small\SwooleEntityManager\Entity\Enum\FieldValueType;
    use MyApp\EntityCollection\UserEntityCollection;

    #[Collection(UserEntityCollection::class)]
    class UserEntity extends AbstractEntity
    {

        #[PrimaryKey]
        public ?int $id = null;

        #[Field(
            type: FieldValueType::string,
        )]
        public ?string $username = null;

    }

You can now use your collection methods on results :

<?php
$youngProspects = $userManager->findBy(['type' => 'prospect'])
    ->getChilds()
;

Basic methods

Generic methods

You can create an empty collection :

<?php
$collection = new \Small\Collection\Collection\Collection();

Or fill it with an array at initialization :

<?php
$collection = new \Small\Collection\Collection\Collection(['map', 'drive', 'country']);

Set a key

<?php
$collection = new \Small\Collection\Collection\Collection(['map', 'drive', 'country']);
$collection->set($key, $value);

Merge another collection

You can merge a collection with another

<?php
$collection = new \Small\Collection\Collection\Collection(['map', 'drive', 'country']);
$collectionBis = new \Small\Collection\Collection\Collection(['map1', 'drive2', 'country3']);

$newCollection = $collection->merge($collectionBis);

Or with an array

<?php
$collection = new \Small\Collection\Collection\Collection(['map', 'drive', 'country']);

$newCollection = $collection->merge(['map1', 'drive2', 'country3']);

And it is possible to act on the source collection

<?php
$collection = new \Small\Collection\Collection\Collection(['map', 'drive', 'country']);

$collection->merge(['map1', 'drive2', 'country3'], true);

Fusion by keys

You can fusion two collection on one on key based comparison

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$collectionBis = new \Small\Collection\Collection\Collection([
    0 => 'map1', 
    1 => 'drive2', 
    2 => 'country3'
]);

$newCollection = $collection->fusionByKey($collectionBis);

Result :

[
  "map1",
  "map",
  "drive",
  "country"
]

It is possible to act on the source collection

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$collectionBis = new \Small\Collection\Collection\Collection([
    0 => 'map1', 
    1 => 'drive2', 
    2 => 'country3'
]);

$collection->fusionByKey($collectionBis, true);

Intersect collections

You can intersect two collections

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$collectionBis = new \Small\Collection\Collection\Collection([
    0 => 'map1', 
    1 => 'drive', 
    2 => 'country'
]);

$newCollection = $collection->intersect($collectionBis);

Result

{
  "2": "drive",
  "3": "country"
}

It is possible to act on the source collection

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$collectionBis = new \Small\Collection\Collection\Collection([
    0 => 'map1', 
    1 => 'drive', 
    2 => 'country'
]);

$collection->intersect($collectionBis, true);

Intersect by keys

You can intersect two collections on key based comparison

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$collectionBis = new \Small\Collection\Collection\Collection([
    0 => 'map1', 
    1 => 'drive', 
    2 => 'country'
]);

$newCollection = $collection->intersectByKey($collectionBis);

Result

{
  "1": "map",
  "2": "drive"
}

It is possible to act on the source collection

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$collectionBis = new \Small\Collection\Collection\Collection([
    0 => 'map1', 
    1 => 'drive', 
    2 => 'country'
]);

$collection->intersectByKey($collectionBis, true);

Values

You can get a collection of values with keys reinitialisation

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$values = $collection->values();

Result

[
  "map",
  "drive",
  "country"
]

Convert collection to array

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$array = $collection->toArray();

The process is recursive :

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country',
    4 => new \Small\Collection\Collection\Collection([1, 2, 3, 4]);
]);
$array = $collection->toArray(false);

Result

[
  "map",
  "drive",
  "country",
  [
    1,
    2,
    3,
    4
  ]
]

Filter by keys

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$array = $collection->filterByKeys([2, 3]);

Result

{
  "2": "drive",
  "3": "country"
}

Filter by values

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$array = $collection->filterByValues(["map", "drive"]);

Result

{
  "1": "map",
  "2": "drive"
}

Filter by callback

<?php
$collection = new \Small\Collection\Collection\Collection([
    1 => 'map', 
    2 => 'drive', 
    3 => 'country'
]);
$array = $collection->filterByCallback(function (int|string $key, mixed $value): bool {
    if ($key >= 3) {
        return true;
    }

    return false;
});

Result

{
  "3": "country"
}

Sort by keys

<?php
$collection = new \Small\Collection\Collection\Collection([
    2 => 'map', 
    1 => 'drive', 
    3 => 'country'
]);
$array = $collection->sortByKey();

Result

{
  "1": "drive",
  "2": "map",
  "3": "country"
}

Sort by values

<?php
$collection = new \Small\Collection\Collection\Collection([
    2 => 'map', 
    1 => 'drive', 
    3 => 'country'
]);
$array = $collection->sortByKey();

Result

{
  "3": "country",
  "1": "drive",
  "2": "map"
}

Sort by callback

<?php
$collection = new \Small\Collection\Collection\Collection([
    2 => 'map', 
    1 => 'drive', 
    3 => 'country'
]);
$array = $collection->sortByCallback(function (mixed $a, mixed $b): int {
    if ($a < $b) {
        return -1;
    } else if ($a > $b) {
        return 1;
    }

    return 0;
});

Result

{
  "3": "country",
  "1": "drive",
  "2": "map"
}

Fill collection with a value

<?php
$collection = new \Small\Collection\Collection\Collection();
$collection->fill("a", 10);

Result

["a", "a", "a", "a", "a", "a", "a", "a", "a", "a"]

Get first value

<?php
$collection = new \Small\Collection\Collection\Collection(['a', 'b', 'c']);

// echo 'a'
echo $collection->first();

Get last value

<?php
$collection = new \Small\Collection\Collection\Collection(['a', 'b', 'c']);

// echo 'c'
echo $collection->last();

Get first key

<?php
$collection = new \Small\Collection\Collection\Collection(['a', 'b', 'c']);

// echo 0
echo $collection->firstKey();

Get last key

<?php
$collection = new \Small\Collection\Collection\Collection(['a', 'b', 'c']);

// echo 2
echo $collection->firstKey();

Push a value

Adding d char to the end of collection

<?php
$collection = new \Small\Collection\Collection\Collection(['a', 'b', 'c']);
$collection->push('d');

Result

["a", "b", "c", "d"]

Pop a value

<?php
$collection = new \Small\Collection\Collection\Collection(['a', 'b', 'c']);
$value = $collection->pop();

Result $value : "c"

Array after pop :

["a", "b"]

Map a callback to collection

<?php
$collection = new \Small\Collection\Collection\Collection([0, 1, 2]);
$result = $collection->map(function (int|string $key, mixed $value) {
    return $value + 1;
});

Result

[1, 2, 3]

Remove keys

Same that values method but apply to $this

Selector

You can select arrays like it was a database table.

You can create use selector to request data in a collection :

<?php
$selector = new Small\Collection\Selector\CollectionSelector(
    (new ValuesToRecords(
        new Collection([1, 2, 3])
    ))->transform()
)->where()
    ->firstCondition(
        new Condition(
            new ConditionElement(ConditionElementType::var, '*'),
            ConditionOperator::equal,
            new ConditionElement(ConditionElementType::const, 2),
        )
    )->orCondition(
        new Condition(
            new ConditionElement(ConditionElementType::var, '*'),
            ConditionOperator::equal,
            new ConditionElement(ConditionElementType::const, 3),
        )
    )
    )->execute()
;

Here, the result will be a Small\Collection\Record\RecordCollection :

<?php
[
    0 => [2],
    1 => [3],
]

Bracket

It is possible to use bracket :

<?php
$selector = new Small\Collection\Selector\CollectionSelector(
    (new \Small\Collection\Record\ToRecordTransformer\CollectionsToRecords(
        new Collection([
            ['test1' => 'a', 'test2' => 'b'],
            ['test1' => 'a', 'test2' => 'c'],
            ['test1' => 'c', 'test2' => 'b'],
            ['test1' => 'd', 'test2' => 'b'],
        ])
    ))->transform()
)->where()
    ->firstCondition(
        new Condition(
            new ConditionElement(ConditionElementType::var, 'test1'),
            ConditionOperator::equal,
            new ConditionElement(ConditionElementType::const, 'a'),
        )
    )->andBracket()
        ->firstCondition(
            new Condition(
                new ConditionElement(ConditionElementType::var, 'test2'),
                ConditionOperator::equal,
                new ConditionElement(ConditionElementType::const, 'b'),
            )
        )->orCondition(
            new Condition(
                new ConditionElement(ConditionElementType::var, 'test2'),
                ConditionOperator::equal,
                new ConditionElement(ConditionElementType::const, 'c'),
            )
        )
    )->execute()
;

Here, the result will be a Small\Collection\Record\RecordCollection :

<?php
[
    0 => ['test1' => 'a', 'test2' => 'b'],
    1 => ['test1' => 'a', 'test2' => 'c'],
]

Comparators

<?php
ConditionOperator::equal
ConditionOperator::inferior
ConditionOperator::superior
ConditionOperator::inferiorOrEqual
ConditionOperator::superiorOrEqual
ConditionOperator::notEqual
ConditionOperator::like // joker char _ and joker string *
ConditionOperator::notLike // joker char _ and joker string *
ConditionOperator::matchRegex
ConditionOperator::notMatchRegex
ConditionOperator::isNull
ConditionOperator::isNotNull
ConditionOperator::exists
ConditionOperator::notExists
ConditionOperator::in
ConditionOperator::notIn

For example :

<?php
$selector = new Small\Collection\Selector\CollectionSelector(
    (new \Small\Collection\Record\ToRecordTransformer\CollectionsToRecords(
        new Collection([
            ['test1' => 'a', 'test2' => 'b'],
            ['test1' => 'a', 'test2' => 'c'],
            ['test1' => 'c', 'test2' => 'b'],
            ['test1' => 'd', 'test2' => 'b'],
        ])
    ))->transform()
)->where()
    ->firstCondition(
        new Condition(
            new ConditionElement(ConditionElementType::var, 'test1'),
            ConditionOperator::equal,
            new ConditionElement(ConditionElementType::const, 'a'),
        )
    )->andCondition(
        new Condition(
            new ConditionElement(ConditionElementType::var, 'test2'),
            ConditionOperator::in,
            new ConditionElement(ConditionElementType::const, ['b', 'c']),
        )
    )->execute()
;

Here, the result will be a Small\Collection\Record\RecordCollection :

<?php
[
    0 => ['test1' => 'a', 'test2' => 'b'],
    1 => ['test1' => 'a', 'test2' => 'c'],
]

Next chapter : Query builder