Here is my implementation:
I use the interface so that the signUp function accepts different types of parameters for each type of user;
Created Interface:
namespace main; interface UserInterface { }
You can add a method that must be implemented for each class. For now, just using this as an hinting object for signUp ();
Using a hint like signUp (User $ user), it will solve your problem regarding the different types of signatures passed in registration. It can be user types admin, manager, salesman and customer. Each {User} entry extends and implements an abstract factory, but differs from the implementation.
I assume that for each type of user there is a corresponding / unique behavior. I added additional classes with the name: AbstractUser.php, UserAdmin.php, UserManager.php, UserSalesman.php and UserCustomer.php. Each class will contain different types of users and attributes, but it expands the user of the abstract class, which is common for each class (email address, name, password);
AbstractUser.php - I notice common user attributes, so I created an abstract user. common attributes (email address, name, password)
<?php namespace main; abstract class AbstractUser { public $email; public $name; public $password; public function __construct($email, $name, $password) { $this->email = $email; $this->name = $name; $this->password = $password; } }
Rewrite your UserFactory.php. But this time it includes the interface that we created UserInterface.php as User;
namespace main; use main\UserInterface as User; abstract class UserFactory { const ADMIN = 'AdminRecord'; const MANAGER = 'ManagerRecord'; const SALESMAN = 'SalesmanRecord'; const CUSTOMER = 'CustomerRecord'; public static function manufacture($type) { return new $type; } protected $accountController; protected $emailController; protected $toolMailer; function __construct() { $this->accountController = new \stdClass(); $this->emailController = new \stdClass(); $this->toolMailer = new \stdClass(); } abstract public function signUp(User $user); }
Pay attention to the signUp () method; I am printing a hint with the created interface, this means that it will only accept the user of the object with the User instance (implements the user interface).
I assume the following code codes are self-explanatory:
UserAdmin:
<?php namespace main; use main\AbstractUser; class UserAdmin extends AbstractUser implements UserInterface { public $companyId; public $access; public function __construct($email, $name, $password, $companyId) { parent::__construct($email, $name, $password); $this->companyId = $companyId; $this->access = UserFactory::ADMIN; } }
AdminRecord: signUp (User $ user) Should only accept an instance of UserAdmin.php
<?php namespace main; use main\UserFactory; use main\UserInterface as User; class AdminRecord extends UserFactory { protected $accountCompanyController; function __construct() { parent::__construct(); $this->accountCompanyController = new \stdClass();
Rewrite your abstract StaffRecord.php: (no change, I think)
<?php namespace main; use main\UserFactory; abstract class StaffRecord extends UserFactory { protected $staffController; function __construct() { parent::__construct(); $this->staffController = new \stdClass();
UserManager:
<?php namespace main; use main\AbstractUser; class UserManager extends AbstractUser implements UserInterface { public $shopId; public $access; public function __construct($email, $name, $password, $shopId) { parent::__construct($email, $name, $password); $this->shopId = $shopId; $this->access = UserFactory::MANAGER; } }
ManagerRecord:
<?php namespace main; use main\StaffRecord; use main\UserInterface as User; class ManagerRecord extends StaffRecord { public function signUp(User $user) { $accountId = $this->accountController->add($user->name, $user->password); $this->emailController->add($user->email, $accountId); $this->staffController->add($accountId, $user->shopId, $user->access); $this->toolMailer->managerWelcome($user->name, $user->email, $user->password); } }
UserSalesman:
<?php namespace main; use main\AbstractUser; class UserSalesman extends AbstractUser implements UserInterface { public $cpf; public $access; public $shopId; public function __construct($email, $name, $password, $cpf, $shopId) { parent::__construct($email, $name, $password); $this->shopId = $shopId; $this->cpf = $cpf; $this->access = UserFactory::SALESMAN; } }
SalesmanRecord:
<?php namespace main; use main\StaffRecord; use main\UserInterface as User; class SalesmanRecord extends StaffRecord { public function signUp(User $user) { $accountId = $this->accountController->addSeller($user->name, $user->password, $user->cpf); $this->emailController->add($user->email, $accountId); $this->staffController->add($accountId, $user->shopId, $user->access); $this->toolMailer->salesmanWelcome($user->name, $user->email, $user->password); } }
UserCustomer:
<?php namespace main; use main\AbstractUser; class UserCustomer extends AbstractUser implements UserInterface { public $cpf; public $phone; public $birthday; public $gender; public function __construct($email, $name, $password, $phone, $birthday, $gender) { parent::__construct($email, $name, $password); $this->phone = $phone; $this->birthday = $birthday; $this->gender = $gender; $this->access = UserFactory::CUSTOMER; } }
CustomerRecord:
<?php namespace main; use main\UserInterface; use main\UserInterface as User; class CustomerRecord extends UserFactory { protected $customerController; function __construct() { parent::__construct(); $this->customerController = new \stdClass();
Here is how I use it:
with loader.php:
<?php function __autoload($class) { $parts = explode('\\', $class); require end($parts) . '.php'; }
php main.php
<?php namespace main; include_once "loader.php"; use main\AdminRecord; use main\UserAdmin; use main\UserFactory; use main\ManagerRecord; use main\UserSalesman; use main\CustomerRecord; $userAdmin = new UserAdmin(' francis@email.com ', 'francis', 'test', 1); $adminRecord = new AdminRecord($userAdmin); $userManager = new UserManager(' francis@email.com ', 'francis', 'test', 1); $managerRecord = new ManagerRecord($userManager); $salesMan = new UserSalesman(' francis@email.com ', 'francis', 'test', 2, 1); $salesmanRecord = new SalesmanRecord($salesMan); //$email, $name, $password, $phone, $birthday, $gender $customer = new UserCustomer(' francis@email.com ', 'francis', 'test', '0988-2293', '01-01-1984', 'Male'); $customerRecord = new CustomerRecord($customer); print_r($adminRecord); print_r($userManager); print_r($salesMan); print_r($salesmanRecord); print_r($customer); print_r($customerRecord);
File Download: https://www.dropbox.com/sh/ggnplthw9tk1ms6/AACXa6-HyNXfJ_fw2vsLKhkIa?dl=0
The solution I created is not perfect and still needs refactor and improvement.
Hope this solves your problem.
Thanks.