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.
Related
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.
Is extending model to a controller a good idea?
Like say I want to make my functions in the model protected instead of public and then extend my model to the controller so that the controller can still call those functions?
Is it a good thing to do? Or should I just leave them public?
No, don't do that! That defeats the whole object of MVC. Leave all functions in the model public unless they are only to be used by that model or related models. In which case they can be private/protected respectively.
If you extend your model to the controller then the controller turns into a model.
I can't imagine how controllers could "extend" your model.
You can extend Eloquent models for example, and make inherited models like:
class ModelB extends ModelA
{
// code
}
class ModelA extends Eloquent
{
protected $something;
//code
}
and then use them in the controller accordingly. Your controllers extend a different class, BaseController and have a different purpose than models to begin with.
So the short asnwer is no.
I am trying to work out the best way to design my classes and I think abstract classes it the right way here, but I'm not sure! I am building a plugin for Wordpress carts that at the moment, will work for both Woocommerce and WP-Ecommerce. As these two systems have different implementations of certain functionality, such as getting an order object, I want to create a separate class for each platform.
I have the following which will contain generic methods that should be available to the classes that inherit from it. This class should never be instantiated:
class Order_Export {
}
I then have 2 more classes that will inherit from the above:
class Order_WooExport extends Order_Export {
}
class Order_WPExport extends Order_Export{
}
Is my design right here? Am I right in saying the class Order_Export should be an abstract class? What about methods that I want the class inheriting to implement? Do I simply mark the signature in the abstract class and not provide a body, or do interfaces come into play somewhere here?
How about instantiating the right class? Do I create a factory that will return one or the other?
Any advice appreciated!
That sound correct to use abstract base class, as long as you are sure to never need to instantiate Order_Export :
abstract class Order_Export
{
abstract protected function someMeth1();
abstract protected function someMeth2();
public function someMeth3() {
// Do common thing to both Order_WooExport and Order_WPExport
// using someMeth1(), someMeth2()...
}
}
Then :
class Order_WooExport extends Order_Export
{
protected function someMeth1() {
// Do something specific
}
protected function someMeth2() {
// Do something specific
}
}
Finally, the factory seems to be the right way to go too.
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.
I haven't used abstract classes much in practice, though I understand what they are : a way to dictate to subclasses which methods must be implemented.
I just put a Kohana project through Doxygen and can see the class hierarchy in its entirety. I see that, at the top of the chain we have a factory:
abstract class Kohana_Model {
public static function factory($name){
// Add the model prefix
$class = 'Model_'.$name;
return new $class;
}
}
Inherited directly below that, we have an empty abstract class:
abstract class Model extends Kohana_Model {}
... And below that, there are three inherited classes: Kohana_Model_Database, Kohana_ORM, and Model_Foobar.
Would someone please explain the programming reasoning for this - what is the purpose of having an empty abstract class this high up in the chain? (and, at all?)
Why not have Kohana_Model_Database, Kohana_ORM, and Model_Foobar inherit directly from Kohana_Model, when there is (apparently?) no other branching or inheritance going on between Model and Kohana_Model?
Answers you're seeking for are Cascading File System and Transparent Extensions.
It allows you to create a model by calling
class News_Model extends Model
by default, and that will automatically then extend Kohana_Model and things will be hunky dory.
It also lets you extend Kohana_Model by creating your own Model file
class Model extends Kohana_Model
which overrides the abstract Model class, and allows you to add custom functionality. Then, when you upgrade your Kohana version to (say) 3.4, your extended Model doesn't get overwritten by the new Kohana files.