CakePHP: Administrator model that can create other models - cakephp

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.

Related

Django, relate User with another table

So I got the tables you can see in the image below:
.
What I would like to do is to create a relationship so that each user (of django auth_user) will be enrolled(or able to enrol) to exactly one "course" so that he will be able to see next events for his modules.
Do I have to create another table and place 2 foreign keys or this is a way to do it in 'php' and it's more simple with Django? I was suggested to create 'student' model inheriting from 'User' with extended behavior and one to many relationship on auth. I tried to do that but unfortunately had not results since I'm really new to Django & Python.
If every auth_user (or auth.User) will be or have the opportunity to be enrolled on a course I would create a 'user profile' model that has a 1-to-1 relationship with the django User model. You can store additional User data in this model, including what course they are enrolled on. See https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model for more details but here is an example:
class UserProfile(models.Model):
user = models.OneToOneField('auth.User')
course = models.ForeignKey('courseapp.Course', null=True)
You would probably need to create a signal that gets fired each time an auth.User object is saved, such that if it is the first time that User object has been saved, it automatically creates the UserProfile:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from yourusersapp.models import UserProfile
def create_user_profile(sender, instance, created, **kwargs):
# Automatically creates a UserProfile on User creation.
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
When you query a User object, you can then reference the User object's profile like:
user_object.userprofile
You could then create a Course object and link the user_object indirectly via its UserProfile to that Course:
course = Course.objects.create(name='course_name', next_field='whatever')
user_profile = user_object.userprofile
userprofile.course = course
userprofile.save()
Now you have a user object with a UserProfile that is linked to only 1 course. Many users can be on the same course, but a user can only be on 1 course. You can also reference all users on a particular course like:
course = Course.objects.get(name='course_name')
course_users = course.userprofile_set.all()
HTH
I think that you can go about this one of two ways.
Extend the User model. 'Student' would probably be a good name for your new model. It would have a OneToOne relationship with 'User', and a ForeignKey relationship with 'Course'. It can store any other information that is applicable to students only. Documentation for how to do that can be found here https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#extending-the-existing-user-model
Create a custom User model that has a ForeignKey relationship with Course. This approach is a bit more complicated, but yields a slightly cleaner end result. Documentation for that is here. https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#substituting-a-custom-user-model
Sorry if it seems like I'm just sending you to the Django docs, but both of those sections are well written and should explain things pretty clearly. If you'd like to post another question with example code we can try and see why your original attempt at extending the User model didn't work. By the way, your "Student" model shouldn't have to inherit from the User model in order to extend it.

Assigning field values before saving on different models

I continue building my CakePHP application. Now I've created all the database schema in MySQL, run some "cake bake all" and I have lots of models, views and controllers, and I'm gonna personalize them.
In many of my models I have this fields:
company_id
created_by
modified_by
As you can understand, the first field is the id of the owner of the "row", created_by is the id of who created the row and modified_by the latest person who updated it.
I know I can create a beforeSave filter in the model and update all the data (I suppose that I can know if I'm creating or updating a row, isn't it?), but just now I have 15 different models and I hope the app will grow more, so it's a lot of repetitive code to write. And, it breaks the DRY principle.
And my question is: Is there any "elegant" way to solve this problem? Maybe creating a class extending AppModel with a beforeSave filter for updating the fields, and that all my models inherit from the new Model class instead of AppModel?
Thanks for your help!
Make it a behaviour and load it for models that need that functionality.
See http://book.cakephp.org/2.0/en/models/behaviors.html#creating-behaviors
I think the most appropriate way is to create Behaviors.
You can set up the beforeSave callback in the behavior like what you have in your model.
Here is the link to the documentation http://book.cakephp.org/2.0/en/models/behaviors.html#behavior-callbacks
You can also check as example dereuromark's WhoDidItBehavior.

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.

Load model or $uses array which need to be used ? while we accessing other models

I have a users controllers, I need to use photos model on that users_controllers
which can i use to access that model from the following and which is standard to use?
$this->loadModel('Photo');
or
var $uses =array('User','Photo');
Load model or $uses array which need to be used ?
Like Anh said, it's best to access the model through relations: $this->User->Photo->whatever(). If the models aren't related, use $uses or loadModel().
The models in $uses are loaded every time the controller is used so it's best to use it only when the other model is needed throughout the controller. If you only need it randomly then loadModel() is better.
The standard is having Photo and User model relate to each other (directly or indirectly): maybe
Photo belongsTo Album belongsTo User.
loadModel or uses: just use the one that is more convenient to you.

cakephp how to have a controller class that other controllers extend

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.

Resources