Strategies for cleanly extending Propel Models in Symfony2? - php

I want to do this:
// Model class
namespace Bookshop\Inventory\Model;
use Core\Inventory\Model\Product as BaseProduct;
class Book extends BaseProduct {
// ...
}
// Query class
namespace Bookshop\Inventory\Model;
use Core\Inventory\Model\ProductQuery as BaseProductQuery;
class BookQuery extends BaseProductQuery {
// ...
}
Looks fine, right? But:
$book = BookQuery::create()->find($id);
var_dump(get_class($book));
// expected: Bookshop\Inventory\Model\Book
// actual: Core\Inventory\Model\Product
AFAIK this is due to the fact that Propel's relationships are defined at build-time, not runtime... The only way I have found of achieving this is by using the extend behaviour found in the GlorpenPropelBundle and defining the extended classes in my config:
glorpen_propel:
extended_models:
Core\Inventory\Model\Product: Bookshop\Inventory\Model\Book
Fine, it works, but surely there's a better way? Have I missed something, or is this really the only way to extend Models in Propel + Symfony? I really want to use Propel over Doctrine, but things like this leave me thinking that Propel simply isn't suited for projects over a certain size...
(Propel 1.6 + Symfony 2.3 btw)

I'm the creator of GlorpenPropelBundle so i thought i could shed some light on issue :)
Propel does provide model classes for modification but sadly when talking about external Bundle's with their own model that classes are generated inside them. There is no second-level user classes.
In some cases you can however make use of Propel single inheritance behavior - http://propelorm.org/documentation/09-inheritance.html or solution provided by hakre .
If you want to simply add some methods to vendor bundle model, you are out of luck.
In olden times there was http://trac.symfony-project.org/wiki/HowToExtendPropelPluginModel but now there are some cases it will not work - and that is where my bundle goes into action.
If you are inside own application, you can always do class extending in following way (since Propel user classes are generated only once):
namespace Bookshop\Inventory\Model;
//your custom class extending Propel base class
class Book extends \Core\Inventory\Model\om\BaseProduct { ... }
namespace Core\Inventory\Model;
//propel user class extending your custom class
class Book extends Bookshop\Inventory\Model\Book {...}

The issue you have and ask about is as you already wrote about built-time / runtime. As BookQuery::create() is a static method it resolves the model classname to BaseProduct.
This is as well outlined in the Propel manual:
Due to late static binding issues in PHP 5.2, you cannot use the create() factory on an inherited query - unless you override it yourself in the descendant class. Alternatively, Propel offers a global query factory named PropelQuery:
<?php
// Use 'frontendBook' instead of 'Book' in the frontend to retrieve only
// published articles
$books = PropelQuery::from('frontendBook')->find();
Source: Propel Query ReferenceDOCS - scroll down to the very end.
So either override it or specify it.
I hope this solves your issue as it allows you to specify which query and therefore entity class to be used by propel.
The Glorpen Propel Bundle takes a different route by the way, changing the code that is being executed for the static getOMClass method. This smells like a hack in my nose, but it's too early that I judge. You find the code in Behaviors/ExtendBehavior.php.

Related

What is the purpose of using traits to define functions for an interface

Sorry if this is a duplicate question or a common design principle, I have searched around but was unable to find any answers to this question. I'm probably just searching with the wrong keywords.
I have been looking at a popular library Sabre/Event (https://sabre.io/event/) and in the code there is a simple class/inheritance model that I am trying to understand:
The class EventEmitter implements EventEmitterInterface and uses EventEmitterTrait (see below for code).
There is a comment in EventEmitterTrait above the class which says:
* Using the trait + interface allows you to add EventEmitter capabilities
* without having to change your base-class.
I am trying to understand why this comment says this, and why it allows adding capabilities without changing the base class, and how that is different from just putting the routines into EventEmitter itself.
Couldn't you just extend EventEmitter and add capabilities in the derived class?
Simplified code:
// EventEmitter.php
class EventEmitter implements EventEmitterInterface {
use EventEmitterTrait;
}
// EventEmitterInterface.php
interface EventEmitterInterface {
// ... declares several function prototypes
}
// EventEmitterTrait.php
trait EventEmitterTrait {
// ... implements the routines declared in EventEmitterInterface
}
You're basically asking two questions here.
What are interfaces and why are they useful?
What are traits and why are they useful?
To understand why interfaces are useful you have to know a little about inheritance and OOP in general. If you've ever heard the term spaghetti code before (it's when you tend to write imperative code that's so tangled together you can hardly make sense of it) then you should liken that to the term lasagna code for OOP (that's when you extend a class to so many layers that it becomes difficult to understand which layer is doing what).
1. Interfaces
Interfaces diffuse some of this confusion by allow a class to implement a common set of methods without having to restrict the hierarchy of that class. we do not derive interfaces from a base class. We merely implement them into a given class.
A very clear and obvious example of that in PHP is DateTimeInterface. It provides a common set of methods which both DateTime and DateTimeImmutable will implement. It does not, however, tell those classes what the implementation is. A class is an implementation. An interface is just methods of a class sans implementation. However, since both things implement the same interface it's easy to test any class that implements that interface, since you know they will always have the same methods. So I know that both DateTime and DateTimeImmutable will implement the method format, which will accept a String as input and return a String, regardless of which class is implementing it. I could even write my own implementation of DateTime that implements DateTimeInterface and it is guaranteed to have that method with that same signature.
So imagine I wrote a method that accepts a DateTime object, and the method expects to run the format method on that object. If it doesn't care which class, specifically, is given to it, then that method could simply typehint its prototype as DateTimeInterface instead. Now anyone is free to implement DateTimeInterface in their own class, without having to extend from some base class, and provide my method with an object that's guaranteed to work the same way.
So in relation to your EventEmitter example, you can add the same capabilities of a class (like DateTime) to any class that might not even extend from DateTime, but as long as we know it implements the same interface, we know for sure it has the same methods with the same signatures. This would mean the same thing for EventEmitter.
2. Traits
Traits, unlike interfaces, actually can provide an implementation. They are also a form of horizontal inheritance, unlike the vertical inheritance of extending classes. Because two completely different class that do not derive from the same base class can use the same Trait. This is possible, because in PHP traits are basically just compiler-assisted copy and paste. Imagine, you literally copied the code inside of a trait and just pasted it into each class that uses it right before compile time. You'd get the same result. You're just injecting code into unrelated classes.
This is useful, because sometimes you have a method or set of methods that prove reusable in two distinct classes even though the rest of those classes have nothing else in common.
For example, imagine you are writing a CMS, where there is a Document class and a User class. Neither of these two classes are related in any meaningful way. They do very different things and it makes no sense for one of them to extend the other. However, they both share a particular behavior in common: flag() method that indicates the object has been flagged by a user for purposes of violating the Terms of Service.
trait FlagContent {
public function flag(Int $userId, String $reason): bool {
$this->flagged = true;
$this->byUserId = $userId;
$this->flagReason = $reason;
return $this->updateDatabase();
}
}
Now consider that perhaps your CMS has other content that's subject to being flagged, like a Image class, or a Video class, or even a Comment class. These classes are all typically unrelated. It probably wouldn't make much sense just to have a specific class for flagging content, especially if the properties of the relevant objects have to be passed around to this class to update the database, for example. It also doesn't make sense for them to derive from a base class (they're all completely unrelated to each other). It also doesn't make sense to rewrite this same code in every class, since it would easier to change it in one place instead of many.
So what seems to be most sensible here is to use a Trait.
So again, in relation to your EventEmitter example, they're giving you some traits you can reuse in your implementing class to basically make it easier to reuse the code without having to extend from a base class (horizontal inheritance).
Per Sabre's Event Emitter's docs on "Integration into other objects":
To add Emitter capabilities to any class, you can simply extend it.
If you cannot extend, because the class is already part of an existing
class hierarchy you can use the supplied trait.
So in this case, the idea is if you're using your own objects that already are part of a class hierarchy, you may simply implement the interface + use the trait, instead of extending the Emitter class (which you won't be able to).
The Integration into other objects documentation says:
If you cannot extend, because the class is already part of an existing class hierarchy you can use the supplied trait".
I understand it's a workaround when you already have an OOP design you don't want to alter and you want to add event capabilities. For example:
Model -> AppModel -> Customer
PHP doesn't have multiple inheritance so Customer can extend AppModel or Emitter but not both. If you implement the interface in Customer the code is not reusable elsewhere; if you implement in e.g. AppModel it's available everywhere, which might not be desirable.
With traits, you can write custom event code and cherry-pick where you reuse it.
This is an interesting question and I will try to give my take on it. As you asked,
What is the purpose of using traits to define functions for an interface ?
Traits basically gives you the ability to create some reusable code or functionality which can then be used any where in your code base. Now as it stands, PHP doesn't support multiple inheritance therefore traits and interfaces are there to solve that issue. The question here is why traits though ?? Well imagine a scenario like below,
class User
{
public function hasRatings()
{
// some how we want users to have ratings
}
public function hasBeenFavorited()
{
// other users can follow
}
public function name(){}
public function friends(){}
// and a few other methods
}
Now lets say that we have a post class which has the same logic as user and that can be achieved by having hasRatings() and hasBeenFavorited() methods. Now, one way would be to simply inherit from User Class.
class Post extends User
{
// Now we have access to the mentioned methods but we have inherited
// methods and properties which is not really needed here
}
Therefore, to solve this issue we can use traits.
trait UserActions
{
public function hasRatings()
{
// some how we want users to have ratings
}
public function hasBeenFavorited()
{
// other users can follow
}
}
Having that bit of logic we can now just use it any where in the code where ever it is required.
class User
{
use UserActions;
}
class Post
{
use UserActions;
}
Now lets say we have a report class where we want to generate certain report on the basis of user actions.
class Report
{
protected $user;
public function __construct(User $user)
{
$this->user = $user
}
public function generate()
{
return $this->user->hasRatings();
}
}
Now, what happens if i want to generate report for Post. The only way to achieve that would be to new up another report class i.e. maybe PostReport.. Can you see where I am getting at. Surely there could be another way, where i dont have to repeat myself. Thats where, interfaces or contracts come to place. Keeping that in mind, lets redefine our reports class and make it to accept a contract rather than concrete class which will always ensure that we have access to UserActions.
interface UserActionable
{
public function hasRatings();
public function hasBeenFavorited();
}
class Report
{
protected $actionable;
public function __construct(UserActionable $actionable)
{
$this->actionable = $actionable;
}
public function generate()
{
return $this->actionable->hasRatings();
}
}
//lets make our post and user implement the contract so we can pass them
// to report
class User implements UserActionable
{
uses UserActions;
}
class Post implements UserActionable
{
uses UserActions;
}
// Great now we can switch between user and post during run time to generate
// reports without changing the code base
$userReport = (new Report(new User))->generate();
$postReport = (new Report(new Post))->generate();
So in nutshell, interfaces and traits helps us to achieve design based on SOLID principles, much decoupled code and better composition. Hope that helps

Call to static::<function> but function doesn't exist but it works (Laravel 5 Eloquent in particular, but it doesn't really matter)

I have been wondering for a while why this works. I have been working with Laravel 5.1 for a while and now I want to create my own framework (for learning purpose only). At the moment I am into Models and Database connections, and then there is this file. Which is extended by Models, such as Status and User models.
https://github.com/illuminate/database/blob/master/Eloquent/Model.php
This is the abstract Model class which isn't too bad. When setting up a Laravel 5.1 project there will be a User class that extends this, it is the possible to execute
User::where('username', 'Rasmus');
User is the user model that extends the abstract Model class
'username' refers to the the database column
'Rasmus' is what it is looking for in that column, it is my name...
The interesting part and the main thing in this question is that there is no "where" method in the Model class, nor the User class. The Model class does NOT inherit anything. Can someone explain to me why this works, (calling User::where) when the method does not exist.
Good to know is that static::where(...); is called a few times in the abstract Model class as well.
Sincerely, Rasmus Rosengren
A fellow PHP learner
Model's __call() function passes it off to a QueryBuilder instance (with a few steps in between, but that's the fundamental end result).
public function __call($method, $parameters)
{
...
$query = $this->newQuery();
return call_user_func_array([$query, $method], $parameters);
}
__call() is a magic method that lets the application deal with a missing/inaccessible method name. In this case, it allows the various where() methods (including being able to do stuff like definitely undefined functions like whereUsername('Rasmus')) to work.
I'm not programming expert and i do expect better answer on this. However, you might be interested in QueryBuilder at line 447. While on Model.php you could see it uses QueryBuilder on line 27.
As i remember Laravel uses trait for handling several code reuse. It is rather advanced topic - which pretty interesting.

PHP creating objects inside a base controller on demand

So i'm working on a framework (Yes i know it's overdone) and i was brainstorming what would be the best possible approach to achieve dynamic object creation inside a base controller. So i came up with the following solution:
Base controller
abstract class Controller extends Container
{
public function __get($obj)
{
$this->$obj = $this->get($obj)
return $this->obj;
}
{
App controller
class Welcome extends Controller
{
public function actionIndex()
{
$this->view->render('welcome');
}
}
So now let me explain whats happening. The base controller extends a container which is a dependency injection class. It holds closures for creating objects. So when we try to access undefined property in welcome controller it calls the magic __get method.
Then the base controller gets the binding from the DI container and defines it as a property so we can use it.
So everything works exactly as i wanted, but i know that magic methods are slow. I was wondering how would it impact performance when there is dozens of __get calls. Is there a better way of achieving the same thing without defining all classes manually in the base controller?
First of all, that is not a DI Container. What you have there is a Service Locator, which you have inherited. If you user Service Locator with some care, it is a quite good pattern, but people usually abuse it and it turns into an architectural anti-pattern.
When you write extends in your code, it means that when you write class B extends A, you are stating that B is just a special case of A. Controllers are not service locators.
Next .. emm. You seem to be missing the point of controllers withing MVC and MVC-inspired architectures.
A controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).
source: wikipedia
Basically, what you are trying to attemt would both violate the basic principles of the pattern and also ignore Single Responsibility Principle. You would be turning a controller in some variation on Factory.
What this boils down to is: why is your controller producing instance and returning them?

cakephp components and helpers breaks oop logic! How should I proceed?

I have a string manipulation class that I need in views and in controllers also!
I saw that cake reuses code in Components and in Helpers for this type of situations which on my opinion breaks the OOP logic (eg. Session->read)!
Instead of doing this I created a vendor class which I imported in a StringsHelper and in a StringsComponent. I then created an identical function which instanciates the Vendor/String class and returns the results from the corresponding function. This is not quite inheritance and still redundant, but if I change code in my class it changes everywhere.
Is there a better way to do this?
You do not need to wrap this kind of class in a Helper or a Component.
You could simply create a class with static methods and put it in APP/Lib like mentioned by Mark.
<?php
class StringTool{
public static function manipulate($string){
...
}
}
and then use it in whatever class you need, wether in a Component, a Helper, a Model, etc.
<?php
$s2 = StringTool::manipulate($s1);
I asked this same question before. Best place is in app/Libs, where you can put a class with static helper functions that can be used anywhere in your application, including controllers and views.
Import the class using App::import('Lib', 'YourClass')
CakePHP - Where is the best place to put custom utility classes in my app structure?

Adding Functionality to Multiple Base Classes in Propel

I have a group of model peer classes that should all have the same functions. Rather than copying and pasting to each every time I add a new one to the group, I would rather add the functions to a class the model peer classes extend. Unfortunately, as the model peer classes extend from Base classes such as BaseModelPeer, it's not possible.
Propel 1.5 has added a basePeer attribute, which can allow you to set BaseModelPeer to extend from a given class. However, by default, a BaseModelPeer class does not extend from anything. Instead, it just makes all its calls to the BasePeer class, which has different signatures for its functions. By changing the basePeer attribute, the BaseModelPeer extends from your new class, let's call it NewBasePeer, and changes the calls to BasePeer to NewBasePeer. As the signatures differ, though, this just causes it to fall apart!
I am actually trying to follow on from Symfony's Zend Lucene tutorial, moving some of the functions which make items indexable to this NewBasePeer class. One of these functions is doDeleteAll. BaseModelPeer's signature of this function looks like this:
public static function doDeleteAll($con = null)
But inside this function it makes a call like this:
$affectedRows += BasePeer::doDeleteAll(ModelPeer::TABLE_NAME, $con, ModelPeer::DATABASE_NAME);
As BaseModelPeer doesn't extend BasePeer, it's fine. But by changing the basePeer attribute in the schema, the function call changes to:
$affectedRows += NewBasePeer::doDeleteAll(ModelPeer::TABLE_NAME, $con, ModelPeer::DATABASE_NAME);
BaseModelPeer now extends NewBasePeer, meaning for it to override the call to doDeleteAll(), they need identical signatures. Clearly the BaseModelPeer class is now contradicting itself!
Is this a bug with Propel? If not, how is one meant to use the basePeer attribute?
Rather than copying and pasting to each every time I add a new one to the group, I would rather add the functions to a class the model peer classes extend.
The correct way is to define a Propel Behavior

Categories