CakePHP- Saving Related Model Data - php

Ok, lets say there are two associated models, where the main model has a hasMany relationship with the other model. ex Donor hasMany Donations. I have read most of cake's documentation and I also took note of this (from the doc):
'When working with associated models, it is important to realize that
saving model data should always be done by the corresponding CakePHP
model. If you are saving a new Post and its associated Comments, then
you would use both Post and Comment models during the save operation'(http://book.cakephp.org/2.0/en/models/saving-your-data.html)
And as also pointed out by #burzum on another one of my questions : CakePHP - Controller or No Controller? , I am still struggling on how to decide which works best.
So taking the 'Donor and Donation' example mentioned earlier, let's say we want the user to add donation to a donor. So for the user to add a donation, one would need to view a donor, accessing a url of the sort : 'domain/donors/view/1', meaning the user is currently viewing donor with id of 1. Then within that view, let us assume there is button which allows the user to add a donation. Now from what I have been told and from what I read, the add(donation) action should belong to the donationsController.
Let us also assume that the add(donation) action has its own view.. So if I am at 'domain/donors/view/1' the user is redirected to 'domain/donations/add/donor_id:1' where the id of the donor is then retrieved using
$this->request->params['named']['post_id']
and set to the FK like so :
`$this->request->data['Donation']['donor_id'] = $id;
But I have a gut feeling telling me that this is not the proper way to go and it feels like bad practice jumping from one controller to the other, when having associated models.
Any insight on this ? Is there a general rule of thumb one could apply or follow ? Is it ok to redirect the user from the donorsController's view action to the donationsController's add action ?
Thanks in advance!

As far as I know your approach is not wrong, and linking other controllers from a view is normal.
However i prefer (and that's my rule of thumb, i'm not sure is a "best practice") to give the user the change of add an associated model - donations in your case - directly from the view of the "main" model. I've used this kind of approach in my applications, mostly considering the user experience (don't know if it is your case). So, if you are in the edit action of Donor, in the respective view the user can add the Donation and send it to still the edit action of Donor. Here you can save the associated model if the request data are well formatted:
data['Donor'] = array('id'=> XX);
data['Donation'] = array('id' => YY, 'amount' => blabla,...);
$this->Donor->save(data);
That would respect the MVC (no ugly ClassRegistry::Load ... ) and keep the code simple, avoiding to jump from one controller to another.
Just my opinion :D
Regards.

Related

Symfony 2 Forms one to many without collection (only add one item)

I'm building a simple form having a one-to-many relation from an User entity :
User 1..* actions
So basically, in my user form, i have to set the actions property to the collection form type.
I don't want the client to be able to add multiple actions within the form, but only one when editing the user.
The problem is that Symfony 2 form expect to get all the actions from the form on submit, so existing actions are removed from database on flush and only the new one remain.
Any idea ?
If your entity User has an array of Actions, and you create a form type UserType with data_class => User, Symfony expects you to add to that form a collection field for actions, because that's what the entity has.
That's the way Symfony works. Personally I don't like this tight coupling between entities in the model and forms, but it works pretty well for simple apps.
If you want to have a form type that does not match any entity, things won't be so simple, but you'll have more control of things.
You have some options (as far as I know, maybe there're other):
You can move to a task-based UI, by creating another class that represents the data you need to perform an action - in your case you want to edit an user, so you can create a EditUserCommand, which contains 1 and only 1 Action, as long as other fields, most of them probably exactly the same as your User class.
Now you can map your form to this EditUserCommand class, which will contain only 1 action as you want. Obviously later you need to use this command class to get the data you need to edit the user.
Use the empty_data option with a closure that receives the submitted FormInterface, so that you can get the submitted data from there and use it as you want to update the user.
In both options you're breaking the coupling between your User class and your EditUserType form, which means you need to do some more work, but imo it has many benefits.
You can find further reading on this subject here.

How to be more Laravel in a CRUD app?

This is a question about how to create a better application with awesome Laravel. I want to create a CRUD application with multiple forms with user's permissions.
Details:
View. I have 3 forms, for example lets call it cat, turtle and dog. The most important is that they have different number of fields.
Here are forms
Controller. After user filled in the form and pressed save button the controller in the game. All of us know that the thinner controller is the better it is. But I use construction like this:
switch($type)
{
case '1':
//form validation -> move to model
//if all have passed that insert into database
//Show user a message
break;
case '2':
//form validation -> move to model
//if all have passed that insert into database
//Show user a message
break;
//.....
default:
//show message
break;
}
Where variable type equals form's type which has been filled in by a user. But as you can see now the controller is pretty big, and I don't like it. What the best way to do this?
Model.
I have 4 table, dogs_data, turtle_data, cat_data where I store all data from forms and pets_data where I store different metadata about pets above. How does it work? After validation passed insert data into one of these tables and get ID of this insertion. Then create the record in pets_data and insert the ID as pet_id and also insert table_type which will be required to get information from database. I think that it is very weird way to work with database. Here is table's visualisation.
Another problem is - show data. For example user has no permissions to edit data or delete records, but admin can remove, updated and see a lot of data from database. Should I create another controller like AdminController and write there another method which display information only for admin?
My application now:
WebSiteController - display website
AdminController - admin page, there is a method which generate special page to view pets.
UserController - users control panel, there is also method which generate page to view pets, but special for user.
And I think to create something like this
AuthController - special for login\registration\activation\etc
PetsController - create\delete\update\etc and also view in two variation: for user and admin. And idea is to create a method getShowPets($pet_id) (important it is only id from pets_data, not the pets_id) then get permission of the user and generate page.
And so on, I want to re-write my application use DRY rule
So I will very happy if you can give me some good tips about this project.
It looks like you are setting up a polymorphic relation, in which case, I would make everything separate meaning you'd have a model for Cat, Dog, Turtle, and PetData. You'd have controllers for CatController, DogController, and TurtleController. And you'd have a Cat form, a Dog form and a Turtle form, each that also contain inputs for the data you require for your pet_info table.
To create the polymorphic relation, your pet_data table will require some changes. Just change the table column to pet_type. Laravel expects a certain name for this column and for its contents to be the name of a model rather than the name of your table.
Setting up the models for these is very easy, I'll do the PetData and the Dog one to get started.
class Dog extends Eloquent
{
protected $table = 'dogs_data';
protected $timestamps = false;
public function petData()
{
return $this->morphMany('PetData', 'pet');
}
}
class PetData extends Eloquent
{
protected $timestamps = false;
public function pet()
{
return $this->morphTo();
}
}
Can read more about this here... http://laravel.com/docs/eloquent#polymorphic-relations
The idea of having separate models/controllers for everything might seem like a lot of work, but it goes a long way when trying to maintain or add additional animals to your app because you should rarely have to modify production code, taking away the possibility of introducing more bugs when trying to add enhancements to your website.
Now it becomes very easy to save a pet and related pet data without having to worry about the pet_id and pet_type in the pet_data table, Laravel will take care of that for you. The function on your dog controller might look like this...
class DogController extends BaseController
{
public function save()
{
$dog = new Dog;
$dog->name = Input::get('name');
$dog->age = Input::get('age');
$dog->save();
$pet_data = new PetData;
$pet_data->color = Input::get('color');
$dog->petData()->save($pet_data);
}
}
As far as creating another controller for admins, I would say yes, do that. It never hurts to keep parts of your website that you consider different in different files. It not only helps with organization, but again, with separation of concerns, which you should probably read more about.
There are also some fantastic 3rd party options for managing roles. I've used zizaco/entrust before and found it very easy to manage. It might make your life a lot easier when trying to manage who can do what on your web app.

Is there such a thing as a partial domain model?

I’ve built a PHP ‘personal profile based’ website that has a number of ‘Category’ pages, each of which list a number of Profiles.
Category page: Lists profiles (images/names in a gallery-like layout)
Profile page: Shows in-depth information about one person/profile
Im using a kinda-MVC-esque architecture here. So, when a visitor goes to a Profile page, the appropriate Controller asks the ProfileDataMapper to fetch the relevant profile. The ProfileDataMapper returns a fully formed Profile Domain Object to the Controller which then sends it to a Template View.
The domain objects are all populated from arguments to their constructors, and have validation checks in them so that if any arguments are missing or bad, they will throw an error and not be instantiated.
The problems start when I want to list a number of Profiles on a Category page. Here I am asking the DataMapper for an array of Profiles. But it is returning a list of whole complete Profile Objects when I know that in this case I only need perhaps a Name and URL. It is putting too much strain on the MySQL DB behind the mapper.
The obvious solution would be to simple make the DataMapper pull just the few fields I really need for the list. But then my Domain Model validation tests would fail due to missing data (they are expecting all fields).
So now I am thinking I should create a new Domain model called PartialProfile or ListableProfile. This domain model would just have a name/url and would only validate those two fields. The ProfileDataMapper would return PartialProfiles in its list method instead of Profiles. Maybe the Profile could even extend from PartialProfile.
Is this 'partial model' a good way to go? Or should I refactor my validation code somehow? It seems to me I need different 'levels' of validation. Sometimes I need the object with all data. Sometimes I don't.
Thanks kind people!

CakePHP migration leads to making edit to act like add

I have BlocksController and Block model. In cakephp-1.2 I used edit action to edit my application's blocks and it worked fine.
After migration to 1.3 and 2.x I noticed that the edit action leads to saving an edited block as a new record.
In the cakePHP docs I read that in 1.3 the form's helper does not supply the id any more and so the model regarded the process as add.
To solve this issue, I tried to add a hidden field named id with a value of the id of the block is being edited as follows:
<?php echo $this->Form->create('Block', array('class' => 'nice custom'));?>
//The following line is required in cakephp 1.3+
<?php echo $this->Form->hidden('id', array('value' => $block['Block']['id']));?>
The described solution is working fine. However I need to know another way to do that without changing in the view. Does it possible?
TLDR
There are any number of ways to accomplish what you want. The most ideal solution would be to add the id into the view, similar to how you mentioned. But - there are as many options as you can think of.
In View
The easiest (and I would argue the ideal) solution would just be to add the id in your view. You should be able to just add it like this:
echo $this->Form->input('id');
It makes it hidden automatically since it's "id" and it should populate for you as well if you're passing the data correctly to the view.
In Controller
BUT - since your question was how to do it NOT in the view, another option is to do it in the Controller. I don't know your exact project, so change it as you see fit, but before your save, you can always just append the Block's id to the data.
$this->request->data['Block']['id'] = $YOUR_ID;
$this->Block->save($this->request->data);
In Model
This seems like a strange place, but - you if you're storing the ID in session or something, you COULD theoretically add the id here before saving as well.

MVC : Dynamic action links in a view: where to put the business logic (zend2)

So, I am fairly new to Zend 2 and MVC as a whole, and I find myself in a situation where I want to follow best practices to make my code reusable and easy to understand.
The particular scenario I want to deal with is the following. Let's say I am writing an editorial application, where users can send articles, but they need to be approved before they are published. When you access an article /article/view/101 , you get a page with the article info on one side (Status, Author, Date, Title, Body) and on the sidebar you get a set of actions.
The set of actions (links) changes based on the type of user viewing the article (guest, user, reviewer or admin) and also based on the status of the article (draft,finished,published)
So the question is: Where do on the MVC model do I put the business logic to decide which actions (links) to put on the sidebar?
The controller does not seem appropriate because I would be adding Business Logic there, and also adding HTML (bad + bad)
The view does not work either because I would be adding business logic.
A service doesn't seem to work either because it seems I would be either adding HTML, or calling partials from there, and that should not be done either...
The only thing I could think of is doing the Business Logic in a service or helper (since more than one model is needed, article and user) and return an 'array' of actions (no HTML). Then the view processes those to actually get the HTML, but I'm not sure if that is the way to do it, and wanted some experienced input.

Categories