Proper Repository Pattern Design in PHP?

后端 未结 11 786
天涯浪人
天涯浪人 2020-11-29 14:22

Preface: I\'m attempting to use the repository pattern in an MVC architecture with relational databases.

I\'ve recently started learning TDD in PHP, and I\'

11条回答
  •  春和景丽
    2020-11-29 14:56

    I can only comment on the way we (at my company) deal with this. First of all performance is not too much of an issue for us, but having clean/proper code is.

    First of all we define Models such as a UserModel that uses an ORM to create UserEntity objects. When a UserEntity is loaded from a model all fields are loaded. For fields referencing foreign entities we use the appropriate foreign model to create the respective entities. For those entities the data will be loaded ondemand. Now your initial reaction might be ...???...!!! let me give you an example a bit of an example:

    class UserEntity extends PersistentEntity
    {
        public function getOrders()
        {
            $this->getField('orders'); //OrderModel creates OrderEntities with only the ID's set
        }
    }
    
    class UserModel {
        protected $orm;
    
        public function findUsers(IGetOptions $options = null)
        {
            return $orm->getAllEntities(/*...*/); // Orm creates a list of UserEntities
        }
    }
    
    class OrderEntity extends PersistentEntity {} // user your imagination
    class OrderModel
    {
        public function findOrdersById(array $ids, IGetOptions $options = null)
        {
            //...
        }
    }
    

    In our case $db is an ORM that is able to load entities. The model instructs the ORM to load a set of entities of a specific type. The ORM contains a mapping and uses that to inject all the fields for that entity in to the entity. For foreign fields however only the id's of those objects are loaded. In this case the OrderModel creates OrderEntitys with only the id's of the referenced orders. When PersistentEntity::getField gets called by the OrderEntity the entity instructs it's model to lazy load all the fields into the OrderEntitys. All the OrderEntitys associated with one UserEntity are treated as one result-set and will be loaded at once.

    The magic here is that our model and ORM inject all data into the entities and that entities merely provide wrapper functions for the generic getField method supplied by PersistentEntity. To summarize we always load all the fields, but fields referencing a foreign entity are loaded when necessary. Just loading a bunch of fields is not really a performance issue. Load all possible foreign entities however would be a HUGE performance decrease.

    Now on to loading a specific set of users, based on a where clause. We provide an object oriented package of classes that allow you to specify simple expression that can be glued together. In the example code I named it GetOptions. It's a wrapper for all possible options for a select query. It contains a collection of where clauses, a group by clause and everything else. Our where clauses are quite complicated but you could obviously make a simpler version easily.

    $objOptions->getConditionHolder()->addConditionBind(
        new ConditionBind(
            new Condition('orderProduct.product', ICondition::OPERATOR_IS, $argObjProduct)
        )
    );
    

    A simplest version of this system would be to pass the WHERE part of the query as a string directly to the model.

    I'm sorry for this quite complicated response. I tried to summarize our framework as quickly and clear as possible. If you have any additional questions feel free to ask them and I'll update my answer.

    EDIT: Additionally if you really don't want to load some fields right away you could specify a lazy loading option in your ORM mapping. Because all fields are eventually loaded through the getField method you could load some fields last minute when that method is called. This is not a very big problem in PHP, but I would not recommend for other systems.

提交回复
热议问题