Symfony + Doctrine: Models and Inheritance - php

I've separated my models from my entities. I have three models with corresponding entities: Review, RatedReview, and ScoredReview. Their relationship is ScoredReview extends RatedReview extends Review.
So for my models I have:
// Project/ReviewBundle/Model/Review.php
class Review
{
}
// Project/ReviewBundle/Model/RatedReview.php
class RatedReview extends Review
{
}
// Project/ReviewBundle/Model/ScoredReview.php
class ScoredReview extends RatedReview
{
}
Then I implement the entities by extending the models, like so:
// Project/ReviewBundle/Entity/Review.php
use Project\ReviewBundle\Model\Review as BaseReview;
class Review extends BaseReview
{
}
// Project/ReviewBundle/Entity/RatedReview.php
use Project\ReviewBundle\Model\RatedReview as BaseRatedReview;
class RatedReview extends BaseRatedReview
{
}
// Project/ReviewBundle/Entity/ScoredReview.php
use Project\ReviewBundle\Model\ScoredReview as BaseScoredReview;
class ScoredReview extends BaseScoredReview
{
}
So the inheritance is happening on the model side. Doctrine can't seem to see this, and maps them to separate tables. I understand this is because Doctrine only looks for entities extending other entities, not entities extending models.
Is there a better way for me to separate the models from the entities, while retaining the ability to extend entities? Is this where traits come in handy?
Put another way, is there anyway that I can have a tree made of models, and a tree made of entities that extends those models?

I've come up with a solution for this issue, and it does involve traits.
What I'm doing is basically trying to create several variations of a table. The relationship between the reviews is more horizontal than vertical (One type of review might have ratings, another one a video, another both). Traits are apparently perfect for horizontal relationships, so instead of creating models for each variation, I create traits.
So now my "models" look like this:
// Project/ReviewBundle/Entity/Review.php
use Project\ReviewBundle\Model\Review as BaseReview;
class Review extends BaseReview
{
}
// Project/ReviewBundle/Entity/RatedReviewTrait.php
trait RatedReviewTrait
{
}
// Project/ReviewBundle/Entity/ScoredReviewTrait.php
trait ScoredReviewTrait
{
}
And my entities look like this:
// Project/ReviewBundle/Entity/Review.php
use Project\ReviewBundle\Model\Review as BaseReview;
class Review extends BaseReview
{
}
// Project/ReviewBundle/Entity/RatedReview.php
use Project\ReviewBundle\Model\RatedReviewTrait;
class RatedReview extends Review
{
use RatedReviewTrait;
}
// Project/ReviewBundle/Entity/ScoredReview.php
use Project\ReviewBundle\Model\RatedReviewTrait;
use Project\ReviewBundle\Model\ScoredReviewTrait;
class ScoredReview extends Review
{
use RatedReviewTrait;
use ScoredReviewTrait;
}
My models stay separated from my entities and as a bonus I decouple the variations from each other – pretty awesome. The only issue I see is that this requires PHP >= 5.4.

Related

Can a related pair of Models be extended without redefining their relationship?

How do I extend two models without having to redefine their relations to target the 'new' extended model?
Say I have two related Eloquent model: Shop and Item in a package.
Shop defines a HasMany relation to Item.
Item defines a HasOne relation to Shop.
Now say I want to extend both models in some other package. Maybe something like:
class LuxuryShop extends Shop{
protected static function booted()
{
static::addGlobalScope(new LuxuryScope);
}
}
// ...
class LuxuryItem extends Shop{
protected static function booted()
{
static::addGlobalScope(new LuxuryScope);
}
}
The problem I have now is that the relations are still pointing to the 'base' model without the new functionality (be it a scope or anything else);
$anyShops = Shop::with('items')->get();
$anyShops->first()->items; // this is a collection of Item model;
$luxuryShops = LuxuryShop::with('items')->get();
$luxuryShops->first()->items; // this is a collection of Item model;
Is it possible to get 'LuxuryItem' from 'LuxuryShop's items HasMany relation without redefining it in the extended model?
I suspect contextual bindings might have a solution but not quite sure how I'd define it.
Please note that actual use-case is many relations over many models used in different contexts (where each consuming context extends the base model). For only a one-off like this example I'd just go ahead and redefine the relation.
This takes place in Laravel 8
I wonder why don't you use two Traits in order to implements these especial features and use as required in your case, instead of extending your models.
https://www.php.net/manual/en/language.oop5.traits.php

Extending one model with another model in Laravel

I am pretty new to laravel and currently exploring its concepts. In some videos I saw a concept of models inheritance. I wonder if we can use models relationships in laravel 5.6 then why we need to inherit models. In which case we need to or should inherit models.
eg Base Model:
class User extends Authenticatable
{
}
eg Child Model:
Class UserTypeOne extends User()
{
}
eg Child Model2:
Class UserTypeTwo extends User
{
}
Thanks in advance.
You don't really need to inherit Models like class inherit. You should use Eloquent Relationship instead. Prior to development, you have to do proper database designing.
https://laravel.com/docs/5.6/eloquent-relationships

Doctrine get repository of all models that extends given abstract class

I have two models: NoteItem and TaskItem. Both extends from AbstractStreamItem:
abstract class AbstractCommentsItem
{
…
}
class CommentItem extends AbstractCommentsItem
{
…
}
class TaskItem extends AbstractCommentsItem
{
…
}
Now I want to get repository of both models in one getRepository command.
Is it possible somehow? I thought about single table inheritance, but not sure if it's the right approach.
Yes, Single Table Inheritance is a valid solution here. You will be able to do:
$entityManager->getRepository(AbstractCommentsItem::class);
to get a single repository for all subtypes.
I'm actually doing that in my current project.

Class structure possibly needing implementation of composition to mimic multiple inheritance

Here's the basic premise, I'm using an active record pattern for db objects, and I think I need some direction how to organize these classes. And also in general how I could potentially split up my class structure. Hopefully I don't explain this too terribly. If composition pattern is the way to go I may need a little hand holding on a way to implement it.
Let's say there's the ActiveRecord base class, at the bottom of the totem pole that deals with mapping objects to the db and the db to objects.
A child of ActiveRecord is a sort of generic User class, that deals with user sessions, logins, encryption of the password field on save and such.
Another child of ActiveRecord is a ActiveRecordButSlightlyMoreAdvanced class. Usually this class has nothing to do with User, but here's my issue.
I want to have a subclass that wants to be essentially a combination of User and ActiveRecordButSlightlyMoreAdvanced; UserButSlightlyMoreAdvanced, without having to copy paste all of the methods from User. It doesn't make sense for User to extend ActiveRecordButSlightlyMoreAdvanced, as it'd require essentially overriding a bunch of methods that have undesirable behavior for User.
It would make sense for UserButSlightlyMoreAdvanced to extend ActiveRecordButSlightlyMoreAdvanced, but I'd have to copy and paste a bunch of methods from User.
I know some people think better with pictures, so here's the structure illustrated.
Base
class ActiveRecord
{
....
}
Child
class User extends ActiveRecord
{
....
}
Also Child
class ActiveRecordButSlightlyMoreAdvanced extends ActiveRecord
{
....
}
The Problem
class UserButSlightlyMoreAdvanced extends User AND ActiveRecordButSlightlyMoreAdvanced
{
:( :( :(
}
I've been thinking about this problem for about a month now and cannot think of a solution that doesn't place burden of maintaining the objects dually if there's a change to how one of them implements saving. I'm going to experiment with a few solutions over the next couple of days and possibly post what I think was best in this situation.
My guess is that you meant to say this:
class UserButSlightlyMoreAdvanced extends User AND ActiveRecordButSlightlyMoreAdvanced
{
:) :) :)
}
If that is the case, look into traits http://php.net/manual/en/language.oop5.traits.php
You might try using the strategy pattern. In this case you would create your class:
class UserButSlightlyMoreAdvanced extends ActiveRecord implements ActiveRecordButSlightlyMoreAdvancedStrategy
{
private $_strategy;
public function useStrategy(ActiveRecordButSlightlyMoreAdvancedStrategy $s) {
$this->_strategy = $s;
}
}
and make your strategy class:
interface ActiveRecordButSlightlyMoreAdvancedStrategy
{
// Define what this should do here
}
Make a strategy class that implements the above interface.
class ActiveRecordButSlightlyMoreAdvanced implements ActiveRecordButSlightlyMoreAdvancedStrategry {
// Do stuff here
}
Now when you call those advanced methods, both classes implement the same interface, but the UserButSlightlyMoreAdvanced class just passes the requests through to the strategy object:
class UserButSlightlyMoreAdvanced extends ActiveRecord implements ActiveRecordButSlightlyMoreAdvancedStrategy
{
private $_strategy;
public function useStrategy(ActiveRecordButSlightlyMoreAdvancedStrategy $s) {
$this->_strategy = $s;
}
public function someSlightlyMoreAdvancedFunction () {
return $this->_strategy->someSlightlyMoreAdvancedFunction():
}
}
Hope that helps.

Is it possible to dynamically extend a model in Codeigniter?

my models in CI are set up so that they load "sub"-models whenever they need certain functions. In order to keep my code as accessible and clean as possible, I want those submodels to extend the model they are called to.
So if I have two models:
<?php
class Mymodel extends Model
{
}
And:
<?php
class Submodel extends Model
{
function test() { do something.. }
}
Then I need to, somehow, be able get the submodel to extend mymodel, so that I can do something like $this->mymodel->test(). It doesn't have to be mymodel that submodel extends, it could be any model. Any ideas?
Thanks for your time.
You have an incorrect understanding of inheritance between classes.
Inheritance only flows one way, Down.
if Myodel extends Submodel your $this->mymodel->test() would work, but it does not make sense as sub (child) objects are suppose to inherit from parent objects, not the other way around.
As an analogy, you wouldn't look at a child and tell the parent, "You look just like your child", because it is the child that is a part representation of the parent.
you need to take the word extends very literally, you are literally 'extending' the functionality of the parent.
===================
One way i believe you could accomplish this is to create ghost functions that simply load the proper model and call that models function (though I do not recommend this as it could get very confusing for debugging.
per your example
<?php
class Mymodel extends Model
{
function test() {
$this->load->model('submodel');
$this->submodel->test();
}
}
Submodel
<?php
class Submodel extends Model
{
function test() { do something.. }
}
BUT again, if you are going for clean code, this is NOT the way to go, try and observe inheritance, and design your data with that in mind.
You can create utility model which may extends codeigniter's model and then all your models can extend that utility model. The methods you are going to add to the utility model will be available to all it's child classes aka your models.
How can you call a method which your class does not have or does not inherit from any other classes? Looking at your code, there is no relationship in your classes between Mymodel and Submodel.

Categories