cakephp how to have a controller class that other controllers extend - cakephp

I want a ThingsController that extends AppController. My individual controllers will extend ThingsController. The functions are repetitive for each model, and each model has its own mainly redundant controller.
A) Is this a good idea?
B) How do I do it? I tried adding it to the controllers directory, but cake did not find it.
c) How should I code in beforeFilter and beforeRender? That includes Auth.

It will work fine. Controllers are nothing more than php classes, you can have them inherit any way you like, so long as Cake can find them.
Create your ThingsController and place it in app/controllers/things_controller.php
In your derived controller, add App::import('Controller', 'Things'); above the class definition.
Define the class properly: class TestController extends ThingsController {}
Filters will inherit like normal.

nowadays you can use App::uses('ClassName', 'Folder/Subfolder')
extending a class does nothing for you in terms of tables in the database... as soon as you extend a model, your extended model name is the table name that cake will look for in the database. you don't get to store the common fields in a common table, and the extended fields in the extended class' table. for that you need model associations anyway, so there's not much point extending models and controllers in cakePHP. to have multiple models deal with the same table, you'd override the table the model uses in the Model definition with $useTable, but I can't imagine much point in that other than your project needs to talk to tables that you can't rename.
so in your case I would say Automobile extends AppModel, Car extends AppModel, Truck extends AppModel, (normal cake models) Truck $belongsTo Automobile, Car $belongsTo Automobile. put your common properties and methods in Automobile just like as if you were going to extend from Automobile, and instead of inheriting the methods, you access them by model association as in $this->Truck->Automobile->vin with object notation rather than with $this->Truck->vin which is what you want to do with inheritance.
in other words you won't get any closer to database normalization by extending Models in cakePHP -- that is done through model associations. you inherit from AppModel and AppController in order to get the basic methods like find(), save() etc and callbacks like beforeFilter() and afterRender(), etc. WRT your question, when you override the callbacks like beforeFilter() in an extending class, you have to call parent::beforeFilter() inside the method or things will break.
i suppose you could have a table with all the fields for the extended properties in it (table automobile with fields year, vin and also box_length, trunk_litres), then extend Models from the base class and override the table which the extended models use to use the base class table name (class Car extends Auto {$useTable = auto}), but this leaves lots of empty fields in the table and is not a proper normalized table structure. it would be a way to have say, VIN be a unique field among all the extended classes without much effort though. not sure how the auto_increment for the ID works in that case though. but then it takes extra work to extract from that common table records of a given type that match the extended class' type (table auto has field auto_type, class Truck extends Auto {$autoType = 'truck'}), so no gain.
similarly there is no gain with views. if you have class AutoController extends AppController { function displayListing()} and then class TruckController extends AutoController you can call TruckController->display_listing() but unless you tell the action to $this->render('Auto/display_listing') you will need to create a duplicate of the view in /View/Truck/display_listing.ctp, and if you do the override, then the view in View/Auto/display_listing.ctp will have to have many if statements to render the portions of the view specific to Truck or Car, so again, no gain.

Related

CakePHP 1.3: extending class unable to find its parent model PHP file

In the class declaration line of the model (.php) files, I'm trying to extend off of a different class then AppModel. Let's say I have some models, including Model, ModelOrder, and ModelLastShipment, etc. And yes, "Model" is a made up name for the sake of generalization.
Model does not use a table and does not have any table association. It extends AppModel. It has some basic functions that I'd like ModelOrder and ModelLastShipment (and other Model... classes) to inherit. The problem is that while ModelOrder can be extended (i.e. class ModelOrder extends Model {...}), I'm unable to do the same with the following because of a missing file error.
model_last_shipment.php:
class ModelLastShipment extends Model {...}
This returns the error,
Fatal error: Class 'Model' not found in C:\xampp\htdocs\my_app\app\models\model_last_shipment.php on line 3
Including include_once('model.php') before the declaration solves this issue, but why does the extension work for ModelOrder without explicit inlcusion but not for ModelLastShipment?
Please let me know if there is more information needed to resolve this. There are many articles and posts regarding this sort of error, but I've yet to find out why I'm getting this error for one and not for another.
Let's say I have some models, including Model
It's impossible to create a class named "Model"
Model is a core class. If you create a class named Model, it with either not be loaded (because the class Model already exists) or cause fatal behavior - possibly "at random".
The class structure in the question is:
Overloadable (Cake)
Model (Cake)
AppModel (App)
Model (App) <- problem
That cannot work. Class names must be unique and Model is a core class.
Including include_once('model.php') before the declaration solves this issue
Are these model class names made up? As stated above that isn't possible with a class named Model.
Intermediary class models are not automatically loaded
These are the only model classes that are loaded automatically in Cake 1.3:
Model
AppModel
AppModel (when appropriate)
If the class hierarchy of your models is such that there are more intermediary classes - they need to be loaded explicitly:
<?php
App::import('Model', 'SomethingElse');
class NotNamedModel extends SomethingElse {

How does cakePHP naming convention work?

I'm relatively new to PHP. Started learning PHP, but then come across cakePHP, which is suppose to speed up development time.
After reading the documentation and blog tutorial I still don't understand the naming convention. I guess I won't know until I start to do some examples, but to get me started can someone please explain to me how cakePHP associate database tables to the controller/model layer?
The below code is an abstract from the tutorial. It is a controller method that passes the post id to the view layer. The database table is called "posts". $this->Post refers to the model class of Post, which correlates to the plural form of posts in the database.
public function view($id = null) {
$this->Post->id = $id;
$this->set('post', $this->Post->read());
}
OK I get that. Then, in the documentation it refers to the following correlation:
ReallyBigPerson and really_big_people
So it seems like the correlation actually follows the rule in English semantics. Does this mean that cakePHP has a list of singular and plural words hidden somewhere that it works from? For example can I use the below correlation without breaking the code?
This and these or Man and men or Foot and feet or Moose and moose or Goose and geese
Furthermore, if I have both singular and plural form of tables in my database, will it break the code, or will it just associate to the plural-formed table?
Just find it baffling... Why couldn't they just match the naming convention like for like with prefixes?
Inflector
CakePHP uses its Inflector class to determine the plurals of things.
Since the naming conventions dictate that model names are singular and tables names are pluralised, it uses the inflector to apply English semantics / rules to determine the plural.
If you need some help understanding the output of the Inflector, you can use the CakePHP inflector website.
Pluralisation Examples
Model name: Post
Table name: posts
Model name: User
Table name: users
Model name: Sheep
Table name: sheep
Model name: News
Table name: news
Model name: Radius
Table name: radii
Check the Inflector site to be sure.
Non-standard Table names
While CakePHP offers a standard rule set for naming and conventions, none of it is set in stone. If you want to change the name of the table used for a particular model, simply specify the table name in the model:
class Thing extends AppModel {
public $useTable = 'somethings';
}
Or, if you want a model that does not use a table:
class Post extends AppModel {
public $useTable = null;
}

cakephp: abstract classes, factory, return objects

I would need an idea or two how I would do this in cakephp (using latest version)
I am building a web based game where you will be able to collect Items
Without a framework I would have an abstract base item class that every item would extend to
And when displaying for example a inventory i would factory all items the user currently have and then return a object for each item.
classes...
BaseItem
WeaponItem
HealingItem
etc..
How would I do this in cakephp? Would I go for a model for each item class ... and how would i factor to get the object? ...
Assuming you're using a database as the data store, presumably you will use a single table for all items the player can collect? If so, you probably want a single Model class.
It's possible to have an inheritance hierarchy for models in CakePHP if you want. But you can often achieve sharing of Model logic using a Behaviour.

CakePHP: Administrator model that can create other models

I have the following models: Students, Teachers, Administrator
What I want to do is have an Admin menu, where I can list all the students and teachers, create new, and edit them too.
What would be the best way to achieve this? Import the model into the admin controller?
As #Anh says, the most straight forward way is to have admin_ actions in the student and teacher controllers respectively. You can access any model from any controller. If you want to list teachers in the students controller or vice versa, you can do so.
By default, a controller only imports the model of the same name. If that model is associated with other models, you can access the other models through the association like $this->Student->Teacher.
If you're going to do this often in a controller, simply load the necessary models directly into the controller using the $uses property:
class StudentsController extends AppController {
public $uses = array('Student', 'Teacher');
}
Now you have both models available directly.
Use prefix routing. In the teacher controller, create actions for admin (admin_index(), admin_add(), etc.) that can add/edit/remove records of teachers. Same for student controller.
Edit: the controller is where you can manipulate a particular model (and related models). If you want both students and teachers on a certain page, are these 2 models related to each other? Wait, aren't they both Users of the website? So what you want is: Admins can CRUD Users, right? So you can have all users listed in admin/users/index page (What I want to show here is: a problem can sometimes lead to a new db design, because you realize what you actually want these models to be).
Either that, or you can make a quick and dirty fix by either: loadModel in a controller of your choice, or use $uses, or make an arbitrary relationship between Teacher and Student.

DRY unique objects in Django

I want to ensure an object is unique, and to throw an error when a user tries to save it (e.g. via the admin) if not? By unique, I mean that some of the object's attributes might hold the same values as those of other objects, but they can't ALL be identical to another object's values.
If I'm not mistaken, I can do this like so:
class Animal(models.Model):
common_name = models.CharField(max_length=150)
latin_name = models.CharField(max_length=150)
class Meta:
unique_together = ("common_name", "latin_name")
But then each time I refactor the model (e.g. to add a new field, or to change the name of an existing field), I also have to edit the list of fields in the parenthesis assigned to unique_together. With a simple model, that's OK, but with a substantial one, it becomes a real hassle during refactoring.
How can I avoid having to repeat typing out the list of field names in the unique_together parenthesis? Is there some way to pass the list of the model's fields to a variable and to assign that variable to unique_together instead?
Refactoring models is a rather expensive thing to do:
You will need to change all code using your models since field names correspond to object properties
You will have to change your database manually since Django cannot do this for you (at least the version I used the last time when I worked with Django couldn't)
Therefore I think updating the list of unique field names in the model meta class is the least issue you should worry about.
EDIT: If you really want to do this and all of your fields must be "unique together", then the guy at freenode is right and you'll have to write a custom metaclass. This is quite complicated and errorprone, plus it might render your code incompatible to future releases of Django.
Django's ORM "magic" is controlled by the metaclass ModelBase (django.db.models.base.ModelBase) of the generic base class Model. This class is responsible to take your class definition with all fields and Meta information and construct the class you will be using in your code later.
Here is a recipe on how you could achieve your goal:
Subclass ModelBase to use your own metaclass.
Override the method __new__(cls, name, bases, dict)
Inspect dict to gather the Meta member (dict["Meta"]) as well as all field members
Set meta.unique_together based on the names of the fields you gathered.
Call the super implementation (ModelBase.__new__)
Use the custom metaclass for all your unique models using the magic member __metaclass__ = MyMetaclass (or derive an abstract base class extending Model and overriding the metaclass)

Resources