PHP/Doctrine2 - Implement an interface twice - php

This might be a silly question. I am trying to create a generic repository interface for Doctrine 2 so I can pass it into my controller through direct injection:
//TestController.php
public function __construct(TestRepositoryInterface $p_repository){
//...
}
The method signature for an EntityRepository in Doctrine2 is as follows:
class EntityRepository implements ObjectRepository, Selectable{
//...
}
EntityRepository is missing a few functions that I would like to have in a repository(Add, Delete, Update). So I created a base repository interface and an abstract repository class to encapsulate those functions:
interface RepositoryInterface {
public function add($entity);
public function delete($entity);
public function update($entity);
}
The abstract repository class extends from EntityRepository so I can still get the functionalities of EntityRepository.
abstract class AbstractRepository extends EntityRepository{
public function add($entity){
//...
}
public function add($entity){
//...
}
public function add($entity){
//...
}
}
To tie everything together, I made TestRepositoryInterface extend from RepositoryInterface, ObjectRepository, and Selectable.
interface TestRepositoryInterface extends RepositoryInterface, ObjectRepository, Selectable{
}
Then I can just pass in an implementation of TestRepositoryInterface through direct injection:
class TestImplementation extends AbstractRepository implements TestRepositoryInterface{
//...
}
Or if I am unit testing, it would be easy to create a mock object or test stub.
My only concern is in TestImplementation class. It extends AbstractRepository which already implements ObjectRepository and Selectable (through EntityRepository), and at the same time TestImplementation also implements TestRepositoryInterface which also extends ObjectRepository and Selectable. So TestImplementation is essentially implementing ObjectRepository and Selectable twice (or is it?). It compiles just fine, but is this a valid approach?

It is perfectly OK for a class to implement multiple interfaces that in turn extend common interfaces. The methods are the same so there are no conflicts.
The only thing you need to worry about is implementing interfaces with same named methods but alternative arguments.
Say you have an interface whose implementations need to be iterated. You would probably have it implement\IteratorAggregate.
Now lets say your implementation class extends ArrayCollection (from doctrine common). Because ArrayCollection also implements IteratorAggregate it take care of some of your own interface's definitions for you.
When it comes to mixing interfaces, look for issues with compatibility rather than inheritance.

Related

When to extend interfaces or use multiple interfaces or extend classes with interfaces

After reading http://php.net/manual/en/language.oop5.interfaces.php, I am uncertain when I should extend interfaces or use multiple interfaces or extend classes with interfaces. What criteria does one use to determine which approach to take?
<?php
interface Interface_A
{
public function aaa();
}
interface Interface_B
{
public function bbb();
}
interface Interface_C extends Interface_A
{
public function bbb();
}
class Class_A implements Interface_A, Interface_B
{
public function aaa(){}
public function bbb(){}
}
class Class_B implements Interface_C
{
public function aaa(){}
public function bbb(){}
}
class Class_C implements Interface_A
{
public function aaa(){}
}
class Class_D extends Class_C implements Interface_B
{
//public function aaa(){} //Use parent
public function bbb(){}
}
The one good approach, I think, is to follow Composition over inheritance and Interface segregation principle by default. This automatically will rule out "extend interfaces" and "extend classes with interfaces" for most cases. For the remaining cases, as always, it depends.
Interfaces are contracts, so when a class implements interfaces it shows other classes that it has appropriate methods. This provides the base for Liskov substitution principle.
From your examples:
If some of your classes rely on aaa() method and some of your classes rely on both aaa() and bbb() methods, and none rely on bbb() alone, then, you, in fact, can extend Interface_A and thus add the method to it.
If all previous keeps but some of the classes also rely on bbb() alone, then it is better to have Interface_A and Interface_B. And if you want to enforce both those methods with one interface you can create combined one:
interface Interface_C extends Interface_A, Interface_B
{
}
This is my subjective opinion but extending classes and also implementing the interface is a bit complex from the understanding point of view and not really useful (or I'd rather say not really practical). In general, you implement an interface, so that you can type hint it. If you type hint Interface_B and your Class_D implements it, then you should not care if this class implements any other interfaces. This means, that you can have Class_C as a dependency for Class_D, and simply can avoid using inheritance at all.

Doctrine addFilterConstraint on joined table

I'm using Doctrine Filters in my Symfony 3.x application.
Now, I need to filter a joined table, but the addFilterConstraint method allways receive the inheritance root:
In the case of joined or single table inheritance, you always get passed the ClassMetadata of the inheritance root. This is necessary to avoid edge cases that would break the SQL when applying the filters.
This is (part of) my class:
<?php
namespace AppBundle\Filter;
use Doctrine\ORM\Mapping\ClassMetaData;
use Doctrine\ORM\Query\Filter\SQLFilter;
class DataAbstractionFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
For example, if I had the classes:
class SomeClass {/**/}
class SomeChildClass1 extends SomeClass {/**/}
class SomeChildClass2 extends SomeClass {/**/}
addFilterConstraints will allways receive SomeClass.
Any suggestions? Thanks in advance.

PHPStorm 9 inspection of class inheritance works unexpectable

I'm facing the following issue in PHPStorm 9:
Say I have an interface FieldInterface that has some methods:
namespace Acme;
interface FieldInterface {
public function methodA();
public function methodB();
}
then I have an abstract class that implements base functionality of the interface. That abstract class has the user to implement certain methods, let's say it's methodB in our example:
namespace Acme;
abstract class AbstractField implements FieldInterface {
public function methodA() {
// implement methodA
}
public abstract function methodB(); // have the user implement it
}
And finally I have some ready-to-use class StringField:
namespace Acme;
class StringField extends AbstractField {
public function methodB() {
// implement methodB
}
}
At this point everything's going well. But if I add new method in the FieldInterface, PHPStorm does not say that anything is wrong with AbstractField while it's obvious that I should add public abstract function newMethod(); in there. However, it spots the error in StringField class instead.
It could be understood from the point that abstract classes are made for the purpose of extention, but usually you extend the abstract class rather than implement underlying interface. The whole meaning of making abstract class is to save user's time for implementing the interface. So why PHPStorm forces me to implement interface in concrete class rather than forcing me to implement it in abstract class that is explicitly implements the interface.
So I wonder if it is a bug in PHPStorm, or maybe it's done on purpose. Either way, is there any workaround?
That's how it should be, showing an error in the abstract class would be wrong.
In fact, public abstract function methodB(); is redundant because the abstract class already "inherits" this abstract method from the interface as it does not implement it.
The only workaround is to make AbstractField not abstract.

Mock interface and trait simultaneously

Is it possible to build object like this (implementing interface and using a trait at the same time) in PHPUnit mock builder?
<?php
class FooClassThatD implements BarInterface
{
use BazTrait;
}
I don't think this is possible with the native mock object methods because they use a specific template to mock a class with a trait that doesn't allow any extension points. You can get around it easily with a test-specific class from which you build your mock.
abstract class BarWithBazTraitTestClass implements BarInterface
{
use BazTrait;
}
Create a mock for this class as you would any other abstract class.
$mock = $this->getMockForAbstractClass('BarWithBazTraitTestClass');

PHP : how to have a extended interface for a class that inherite from another class with its own interface?

I have something like :
interface IProduct { }
class Product implements IProduct { }
class SpecificProduct extends Product { }
I need to have a interface, that extends IProduct, for my SpecificProduct.
Can I just do something like :
interface ISpecificProduct { }
class SpecificProduct extends Product implements ISpecificProduct { }
or will it overwrite the IProduct interface ?
This works in PHP, this way, just go through:
class SpecificProduct as it extends Product it implements IProduct already. As it implements ISpecificProduct as well, it has both interfaces.
SpecificProduct now has two interfaces then:
IProduct
ISpecificProduct
Yes, you can do that, and no, it will not "overwrite" IProduct, it adds to it.
In case you are using the ISpecificProduct interface somewhere and would like to know about the methods in IProduct, ISpecificProduct can also extend IProduct:
interface ISpecificProduct extends IProduct
In this case, SpecificProduct gains knowledge of the method signatures from IProduct in two ways.
See PHP documentation on interfaces for more information.
As a side note, if you have a matching interface for every concrete class, there is probably something inefficient or unnecessary going on in your object design.

Categories