I am trying to make a small e-commerce backend in php. I centralized all the static factory methods in a class called EntityFactory. The main reason for that was to centralize the dependency on dependency injector and to make it easy for the client to initialize an entity.

class EntityFactory
    private static $employeeRepository;
    private static $productRepository;

    public static function employee($name, $designation, $salary, $contactNo)
        if (!self::$employeeRepository)
            self::$employeeRepository = resolve(EmployeeRepository::class);

        return new Employee(self::$employeeRepository, $name, $designation, $salary, $contactNo);

    public static function product($itemCode, $name, Brand $brand, Category $category, $costPrice, $salePrice)
        if (!self::$productRepository)
            self::$productRepository = resolve(ProductRepository::class);

        return new Product($itemCode, $name, $brand, $category, $costPrice, $salePrice, self::$productRepository);

    public static function brand($name, $id = null)
        $brand = new Brand($name);
        if ($id) $brand->setId($id);
        return $brand;

    public static function category($name, $id = null)
        $category = new Category($name);
        if ($id) $category->setId($id);
        return $category;

    public static function purchaseOrder($customer, $user)
        return new PurchaseOrder($customer, $user);

    public static function orderItem($item, $qty)
        return new PurchaseOrderItem($item, $qty);

The main problem I feel here is that this breaks SOLID, especially SRP, ISP and OCP. I may also face problems regarding unit testing in the future(though I've not yet faced one). The code for product purchasing:

//controller: create a new purchase order
public function store(Request $request)

    $user = $this->productRepository->findById(Auth::id());
    $customer = $this->supplierRepository->findById($request->input('id'));
    $products = $request->input('products');
    $purchaseOrder = EntityFactory::purchaseOrder($customer, $user);

    foreach ($products as $product) {
        $item = $this->productRepository->findById($product['id']);
        $purchaseOrder->addItem(EntityFactory::orderItem($item, $product['qty']));


Here I can easily stub out the repositories in the controller

// class PurchaseOrder

public function addItem(PurchaseOrderItem $item)
    $this->items[] = $item;

public function finalize()
    foreach ($this->items as $item) {
        $product = $item->getProduct();

//class Product
public function purchase($qty)
    if ($this->stock - $qty < 0) {
        throw new \RuntimeException("Product not available");
    } else {
        $this->stock += $qty;

Here also the ProductOrderItem and Product can be stubbed.

I didn't want the factory to need instantiation. Otherwise I would have a dependency graph like factory -> repository -> mapper -> factory where mapper maps data from ORM classes to entity classes.

What are your thoughts?

  • \$\begingroup\$ I think the question is fairly language agnostic as it's mainly about design. However, I'll add the tag if it helps. \$\endgroup\$
    – sayeed910
    Mar 27, 2018 at 14:07


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.