Search code examples
phpdesign-patternsrepository-patternfactory-pattern

Where should I create objects? repository? factory?


I have a repository for my business objects, and I need to create different objects based on the data. Should I create them in the repo directly or move that code somewhere else - to the factory or some class in the business logic layer?

/**
 * @returns Applier
 */
class ApplierRepository implements IApplierRepositoryInterface {
  //some code
  public function find($id) {
    $data = $this->findBySql($id);

    //Is it a business logic?
    if($data['profile_id'] != null)
      $object = new ProfileApplier();
    if($data['user_id'] != null) {
      $user = $this->userRepository->find($data['user_id']);
      $object = new UserApplier($user);
    }
    //...
    return $object;
  }
}

Solution

  • I would consider Repository as an abstraction level between Data Access Level and your application logic. What you have in your find() method is actually a Factory method.

    To make things clear, imagine that you need to test the logic of your class with a testing ramework. What would you do? It seems like your ProfileApplier, UserApplier and other appliers call some datasources to retrive user data.

    In test methods you'll need to replace those data sources with test ones. You will need to replace data source access methods too. And that is what the Repository pattern is designed for.

    More cleaner approach would be something like the following:

    class AppliersFactory {
      IApplierRepository applierRepository;
    
      public AppliersFactory(IApplierRepository repo)
      {
        $this->applierRepository = repo;
      }
    
      // factory method, it will create your buisness objects, regardless of the data source
      public function create($data) {
        if($data['profile_id'] != null)
          $return new ProfileApplier();
        if($data['user_id'] != null) {
          $user = $this->applierRepository->find($data['user_id']);
          $object = new UserApplier($user);
        }
        //...
        return $object;
      }
    }
    

    use this repository in your real application

    class RealApplierDataStorageRepository implements IApplierRepositoryInterface {
      //some code, retrieves data from real data sources
      public function find($id) {
        //...
      }
    }
    

    and use this one in Test modules to test your logic

    class TestApplierDataStorageRepository implements IApplierRepositoryInterface {
      // some code, retrieves data from test data sources (lets say, some arrays of data)
      public function find($id) {
        //...
      }
    }
    

    Hope, it helps