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

Document memory-efficient Entity-Repository pattern #240

Open
g105b opened this issue Oct 8, 2021 · 2 comments
Open

Document memory-efficient Entity-Repository pattern #240

g105b opened this issue Oct 8, 2021 · 2 comments

Comments

@g105b
Copy link
Member

g105b commented Oct 8, 2021

The Entity-Repository pattern is perfect for complementing usage of this repo, but something not obvious from the Entity-Repository Pattern is how it can be utilised in a memory-efficient way.

Basically, any function that returns a collection of Entities should do it via a callback to the original ResultSet.

function getChildren(Entity $parent):EntityCollection<Entity> {
    $resultSet = $this->db->fetchAll("getChildrenByParentId", $parent->getId());

    $entityCollection = new EntityCollection();
    $entityCollection->setIteratorCallback(function() use $resultSet:?Entity {
        $resultSet->next();
        if(!$resultSet->valid()) {
            return null;
        }
        return $this->rowToEntity($resultSet->current());
    });

    return $entityCollection;
}
@g105b
Copy link
Member Author

g105b commented Oct 8, 2021

Original issue text:

The repository pattern is a design pattern that describes an object that represents a mutable list of data, and is perfect for answering the questions raised by #80.

Problem: $row = $database->fetch("customer/getById", 123) it is obvious that here we are querying the customer table and retrieving the row with an ID of 123, but to the code and IDE it is not obvious to what functionality or parameters $row has.

Solution: Use of CustomerRepository, a developer-defined class which is constructed with reference the Customer query collection (promoting database encapsulation).

class CustomerRepository {
	protected $db;

	public function __construct(QueryCollection $db) {
		$this->db = $db;
	}

	public function getById(int $id):Customer {
		$row = $this->db->fetch("getById", $id);
		return new Customer(
			$row->firstName,
			$row->lastName,
			// ... etc.
		);
	}
}

The idea is simple: let the developer have complete control over how the Entity objects are created. For example, it may not be that all Entity object constructors take a Row parameter... so this allows arbitrary classes to be used as Entities.

Strict rule: All database mutations should be done within their own Repository classes. Entities can have functionality, but only functionality that is calculating something based on its own internal data structure.

@g105b
Copy link
Member Author

g105b commented May 9, 2022

<?php
abstract class Entity {}

class User extends Entity {
	public function getUsername():string { return "bob"; }
}

/** @template T */
class Repository {
	/** @return T */
	public function getById(string|int $id):Entity {

	}
}

/** @extends Repository<User> */
class UserRepository extends Repository {

}

$userRepo = new UserRepository();
$user = $userRepo->getById(123);

// This is now type-hinted correctly!
$user->getUsername();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant