Extended class don't need same arguments - php

I have an issue with the way my classes are implemented
I have an abstract class which implements an interface :
interface DriverInterface {
public function __construct(
array $tableGateway,
Sql $sql,
$dbName,
);
public function process();
public function setIdentiteService(IdentiteService $service);
public function setPhotoService(PhotoService $service);
public function setDocumentService(DocumentService $service);
public function setLotService(LotService $lotService);
}
Abstract class:
abstract class AbstractDriverMigration implements DriverInterface {
protected $tableGateway;
protected $sql;
protected $dbName;
public function __construct(array $tableGateway, Sql $sql, $dbName)
{
$this->tableGateway = $tableGateway;
$this->sql = $sql;
$this->dbName = $dbName;
}
abstract public function process();
public function setIdentiteService(IdentiteService $service) {}
public function setPhotoService(PhotoService $service) {}
public function setDocumentService(DocumentService $service) {}
public function setLotService(LotService $service) {}
}
Then I call the classes which extends the abstract class programmatically :
$className = 'Migration\\Driver\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $class)));
$driver = new $className(...);
But the thing is that, for some classes, but not all, I need to pass services with the 'setXService' functions that I override from the abstract class, and I end up testing which class it is to pass the services. And I don't like doing that.
if ($class == 'user' ) {
$driver->setLotService($service)
}
And I don't want to pass the services to all the classes, since some of them don't need them.

Related

Pass in a interface type as a function parameter throws "Delaration must match ..."

I want to be able to pass in an object that implements IEntity interface but I'm facing a
PHP Fatal error: Declaration of ShirtOrderRepository::find(ShirtOrder $shirtOrder) must be compatible with RepositoryInterface::find(IEntity $entity) in /Users/okkamiadmin
/projects/Befeni/index.php on line 52
error how can I achieve this as I'm not sure if I'm doing it the right way?
<?php
interface IEntity {
public function getTableName();
}
class ShirtOrder implements IEntity
{
public $id;
public $customerId;
public $fabricId;
public $collarSize;
public $chestSize;
public $waistSize;
public $wristSize;
public function getTableName()
{
return 'shirt_orders';
}
}
interface RepositoryInterface
{
public function find(IEntity $entity);
public function save(IEntity $entity);
public function remove(IEntity $entity);
}
interface DatabaseInterface {
public function find(IEntity $entity);
public function save(IEntity $entity);
public function remove(IEntity $entity);
}
class ShirtOrderRepository implements RepositoryInterface {
protected $db;
public function __construct(DatabaseInterface $db) {
$this->db = $db;
}
public function find(ShirtOrder $shirtOrder)
{
$this->db->find($shirtOrder);
}
public function save(ShirtOrder $shirtOrder)
{
$this->db->save($shirtOrder);
}
public function remove(ShirtOrder $shirtOrder)
{
$this->db->remove($shirtOrder);
}
}
You need to pass type of IEntity instead of ShirtOrder at ShirtOrderRepository class like so:
public function find(IEntity $shirtOrder){
$this->db->find($shirtOrder);
}
Also you need to do this for the rest of the methods since RepositoryInterface expects type of IEntity passed in its methods parameters.

Multiple DB-Tables in Repository - How to do this?

I have the following Code:
Controller
class UserController {
public function __construct(userRepository $userRepository) {
$this->userRepository = $userRepository;
}
[...]
Repository
class UserRepository extends AbstractRepository {
public function getTablename() {
return "tbl_users";
}
public function getModel() {
return "administration\\CMR\\UserModel";
}
[...]
AbstractRepository
abstract class AbstractRepository {
protected $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
abstract public function getTablename();
abstract public function getModel();
function readAll() {
$table = $this->getTablename();
$model = $this->getModel();
$stmt = $this->pdo->query("SELECT * FROM $table");
$res = $stmt->fetchAll(PDO::FETCH_CLASS, $model);
return $res;
}
[...]
My Problem is, that I need the "tbl_users" for one query and a secound table (tbl_locations) for another query. Could anyone please explain how to do this? I think it's unnecessary to write again the same readAll()-Function only with other variable.
Start by adding location repository
class LocationRepository extends AbstractRepository implements LocationRepositoryInterface {
public function getTablename() {
return "tbl_locations";
}
public function getModel() {
return "administration\\CMR\\LocationModel";
}
[...]
and put both repositories to upper layer, say UserLocationService.
class UserLocationService implements UserLocationInterface {
public function __construct(
protected UserRepositoryInterface $userRepository,
protected LocationRepositoryInterface $locationRepository
) {
}
[...]
}
This way you have separate repositories for users and locations, yet you can operate on both, in Service that does require both repositories to fulfill its' logic.
If I understand correctly, you want to be able to set the tablename to your likings. One possibility is to pass a tablename in the UserRepository constructor (and set a default), like this:
class UserRepository extends AbstractRepository {
public function getTablename() {
return $this->tablename;
}
public function getModel() {
return "administration\\CMR\\UserModel";
}
[...]
abstract class AbstractRepository {
protected $pdo;
protected $tablename;
public function __construct(PDO $pdo, string $tablename = "tbl_users") {
$this->pdo = $pdo;
$this->tablename = $tablename;
}
abstract public function getTablename();
abstract public function getModel();
function readAll() {
$table = $this->getTablename();
$model = $this->getModel();
$stmt = $this->pdo->query("SELECT * FROM $table");
$res = $stmt->fetchAll(PDO::FETCH_CLASS, $model);
return $res;
}
[...]

Using a trait constructor

I have a class which I am going to make Singleton. For this reason, I want to use a trait. Something like this:
trait TSingleton
{
private static $instance = null;
private function __construct() {}
private function __clone() {}
private function __wakeup() {}
/**
* #return static
*/
public static function getInstance()
{
if (is_null(static::$instance)) {
static::$instance = new static();
}
return static::$instance;
}
}
And then:
class Db implements IDb
{
use TSingleton;
...
}
The question is if the Db's constructor would be private also, and if it does, why could I create its inheritors?

DI, ServiceProvider, abstract parent and Laravel 5.3

I have some problem and little misunderstanding Laravel SP (ServiceProvider). I have abstract class Repository and her Interface:
abstract class Repository implements RepositoryInterface {
private $model;
private $parser;
public function __construct() {
$this->model = new $this->model_name();
} }
interface RepositoryInterface {
public function create(array $attributes);
public function update($id, array $attributes);
public function delete($id);
public function all();
public function find($id);
public function filter(array $parameters, $query=null);
public function query(array $parameters, $query=null); }
and some child UserRepository for example:
class UserRepository extends Repository implements UserRepositoryInterface {
protected $model_name = "App\Models\User";
public function __construct() {
parent::__construct();
}
public function activation($user_id) {
return "user";
}
public function deactivation($user_id) {
return "user";
} }
and simple ModelParser class:
class ModelParser {
protected $parameters;
protected $model;
public function __construct($model) {
$this->model = $model;
} }
This work fine, but I would pass ModelParser as DI in my construct of abstract Repository with parameter $model. I dont have idea. How should I do it ?
I use it like this:
class UserController extends Controller {
private $repository;
public function __construct(UserRepository $repository) {
$this->repository = $repository;
} }
Well it's kinda complicated since your ModelParser requires a $model as it's parameter. And because this $model may vary depends on its repository, it will be too complicated if we're trying to resolve it using Laravel service container binding.
There's an easier approach, we can make the ModelParser class's constructor receive an optional $model parameter. Then we can add an additional method to set this $model property like so:
namespace App\Models;
class ModelParser
{
protected $parameters;
protected $model;
// Make $model parameter optional by providing default value.
public function __construct($model = null) {
$this->model = $model;
}
// Add setter method for $model.
public function setModel($model)
{
$this->model = $model;
return $this;
}
}
And now you can inject the ModelParser into your abstract Repository class. Laravel will easily resolve this ModelParser parameter
namespace App\Models;
use App\Models\ModelParser;
use App\Models\RepositoryInterface;
abstract class Repository implements RepositoryInterface
{
private $model;
private $parser;
// Pass ModelParser instance to your constructor!
public function __construct(ModelParser $parser)
{
$this->model = new $this->model_name();
// Set the parser's model property.
$this->parser = $parser->setModel($this->model);
}
// Rest of your code.
}
And if you're extending the abstract Repository class, you still have to pass this ModelParser to the constructor like so:
namespace App\Models;
use App\Models\ModelParser;
use App\Models\UserRepositoryInterface;
class UserRepository extends Repository implements UserRepositoryInterface
{
protected $model_name = "App\Models\User";
public function __construct(ModelParser $parser)
{
parent::__construct($parser);
}
}
Actually, if you're not planning to pass another parameter or perform something else during the class instantiation, you can simply remove the __construct() method from UserRepository and rely on its parent (the abstract Repository).
Hope this help!

Static methods and Singleton in PHP

I have the next class:
class MyClass {
private $_instance = null;
private function __clone() {}
private function __construct() {}
public static function instance()
{
if (is_null(self::$_instance)) {
self::$_instance = new self;
}
return self::$_instance;
}
public static function methodOne() {}
public static function methodTwo() {}
public static function methodThree() {}
public static function methodFour() {}
}
And I have a lot of methods method...(). But this methods can be executable only if instance is not null. How can I throw an exception if instance is null?
I need to use only static methods. I can not use non-static. I want to use the next design:
MyClass::instance();
MyClass::methodOne(); // If no instance throws an Exception.
Do not make the methods static, only keep instance() static.
It will lead to:
$m = MyClass::instance();
$m->methodOne();

Categories