N
N
ndbn2015-09-29 14:27:24
PHP
ndbn, 2015-09-29 14:27:24

How to properly organize classes?

I am mastering the features of php that I have not used before, having moved from php 5.2 to php 5.6 along the way, I learned about PSR-0,1,2,4 by stumbling upon this (PHP Right Way) document.
Here I set the task: to implement the ability to work with different types of storages (git, mercurial).
I make a package in which I implement:

  • Interface: interface RepositoryInterface
  • Abstract class: abstract class RepositoryAbstract
  • Class for working with a repository of type mercurial:
    class RepositoryHg extends RepositoryAbstract implements RepositoryInterface

Further in the code of the site (or application, as you wish), I assume there should be a correct use of the RepositoryInterface interface, in case, for example, the RepositoryGit class appears, but I should not let the site (application) see RepositoryHg or RepositoryGit, if I understand correctly , why OOP at all, because the point is that it does not care what class it is given, the main thing is that it implements the desired interface.
Probably the Factory pattern should be implemented in the RepositoryAbstract and only the interface should be used in the application, but I'm not sure, I'm doing everything for the first time and I'm asking for a hint.
Thank you.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
L
Lesha Kiselev, 2015-09-29
@ndbn

I use this approach:
There are three interfaces EntityInterface, RepositoryInterface, RepositoryDriverInterface

interface EntityInterface extends Serializable {
    public function getId();
}

interface RepositoryInterface {
    public function getDriver();
    public function findById($id, EntityInterface $Entity);
    public function save(EntityInterface $Entity);
}

interface RepositoryDriverInterface {
    public function set($id, $data);
    public function get($id);
}

The repository driver works with the database. The repository itself deals with the serialization / deserialization of entities. Driver examples:
Array driver:
class RepositoryDriverArray implements RepositoryDriverInterface {
    private $data = [];

    public function set($id, $data) {
        $this->data[$id] = $data;
    }

    public function get($id) {
        return $this->data[$id];
    }
}

Driver working with Redis:
class RepositoryDriverRedis implements RepositoryDriverInterface {
    protected $Redis = null;

    public function __construct(Client $Redis) {
        $this->Redis = $Redis;
    }

    public function set($id, $data) {
        $jsonData = json_encode($data);
        $this->Redis->hset($this->getContainerName(), $id, $jsonData);
    }

    public function get($id) {
        $jsonData = $this->Redis->hget($this->getContainerName(), $id);
        $data = json_decode($jsonData, true);

        return $data;
    }

    public function getContainerName() {
        return 'myContainer';
    }
}

An example of the implementation of the repositories themselves:
abstract class AbstractRepository implements RepositoryInterface {
    protected $RepositoryDriver = null;

    public function __construct(RepositoryDriverInterface $RepositoryDriver) {
        $this->RepositoryDriver = $RepositoryDriver;
    }

    public function save(EntityInterface $Entity) {
        $this->getDriver()->set($Entity->getId(), $Entity->serialize());
    }

    public function findById($id, EntityInterface $Entity) {
        $data = $this->getDriver()->get($id);
        $Entity->unserialize($data);

        return $Entity;
    }

    public function getDriver() {
        return $this->RepositoryDriver;
    }
}

Next, we write the business logic:
class User implements EntityInterface {
    // TODO: Implement methods
}
class UserRepository extends AbstractRepository {}

And this is how we work with this whole system:
$Redis = new Client([/* connection params */]);
$RedisDriver = new RepositoryDriverRedis($Redis);
$UserRepository = new UserRepository($RedisDriver);

$User = new User();
$UserRepository->save($User);

$User = new User();
$UserRepository->findById(1, $User);

Writing unit tests? Change the repository driver:
$ArrayDriver = new RepositoryDriverArray();
$UserRepository = new UserRepository($ArrayDriver);

$User = new User();
$UserRepository->save($User);

$User = new User();
$UserRepository->findById(1, $User);

Such a system is very easy to test. The whole "routine" can be wrapped in various facades, "configurators", providers.
I wrote only examples, of course, in a real system there are more driver features, repositories.
Caching should be done at the repository level. The driver is only concerned with saving/loading data.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question