1

I'm developing in PHP using the symfony framework however the question applies more broadly to non-symfony and non-PHP developers also. (For symfony developers, I am using single table inheritance mapping to map the sub-classes to the DB using Doctrine ORM, BasePerson extends FOSUserBundle which is then further extended by two sub-classes.)

"BasePerson" extends the original User class which is further extended into two seperate sub-classes: photographer, PhotoSubject.

Having sub-classes is a nice seperation of logic, however the issue arises when I have a photographer that is also a PhotoSubject. They would share the same email address, but different usernames (in the User class).

However now I have two objects for the same person (the same User): a PhotoSubject and a Photographer, both with different usernames and with potentially different passwords etc which is obviously not possible in Doctrine - they need to be stored as two seperate DB records with differen usernames. Having two different logins for the same user seems like a design problem to me.

Can anyone suggest the correct design for this problem? Should I not use inheritance at all to avoid this problem and instead have a monolithic "BasePerson" class that isn't extended. Should I somehow check the database for another "person" with the same email address when a user logs in? Or is there another solution to this problem?

Brendan
  • 908
  • 2
  • 15
  • 30
  • A similar question was asked 7 hours earlier which has given some useful information: http://stackoverflow.com/questions/37306930/doctrine-inheritance-strategy-when-two-different-subclasses-extend-the-same-enti – cameron cameron May 19 '16 at 02:04

2 Answers2

2

I think you are confusing the inheritance, behavior and the data. In this particular case I'd rather replace the Photographer and PhotoSubject classes with interfaces

interface Photographer {
  /**
    * @param PhotoSubject[] $filter subjects to filter the photos
    *
    * @return Image[]
    */
  public function getPhotos(array $filter);

  public function addPhoto(Image $photo);

  /** @return Image */
  public function shot(PhotoSubject $subject);

  // any other methods
}

interface PhotoSubject {
   /**
     * @return Image[] the images of the subject
     */
   public function getSubjectShots();
}


class Person implements Photographer, PhotoSubject {
  /** @var Image[]|ArrayCollection */
  private $ownImages;
  /** @var Image[]|ArrayCollection */
  private $referencedShots =[];

  public function getPhotos(array $filter) { return $this->ownImages->filter(...)->toArray(); }
  public function addPhoto(Image $photo) { 
     $this->ownImages->add($photo); 
     $photo->setAuthor($this);
  }

  public function getSubjectShots() { return $this->referencedShots->toArray(); }

  public function shot(PhotoSubject $subject) {
     $image = new Image(); 
     $this->addPhoto($image);
     $image->addSubject($subject);

     return $image;
  }
}

You do not really need to have the class for each type of object in the world. You have a single object - a Person and interface allows you to show the Person from different points of view. In physics it is called a "model" - simpified object, describing the params needed at the moment. The same is here, bind to the behavior (interfaces), not the realisation.

ScayTrase
  • 1,810
  • 23
  • 36
1

I think the problem here is that you have confused a relationship with a subtype.

A Photographer might be a type of person, so long as it doesn't cause you similar issues down the road with mutual exclusivity, but a photoSubject isn't a type of Person.

A Photosubject should be a relationship between a photo and a person (1 Photo -> Subjects/Persons)

gview
  • 14,876
  • 3
  • 46
  • 51
  • hi gview, thanks for the input, however I still need a sub-class of BasePerson that represents someone in a photo. This class would then implement methods such as "getImages()" for that "photo subject" in the way that Photographer implements methods. – cameron cameron May 19 '16 at 12:07
  • Yes, but again, that type of function, should be discovering relationships from Person to Photo. In other words, I would make something like that part of the Photo class. Photo.findImages($person=null); In regards to Doctrine, you're going to put the code that does the work into a Custom Repository class for your Photo class. – gview May 19 '16 at 16:50