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.
Related
I have a form in my Yii2 project and I need to allow for multiple models to be created using it. Overall I have a single Group and multiple Person ActiveRecords that will be created using the form, and each Person record will belong to the Group.
For example I have this class that is the form:
<?php namespace app\models\forms;
class GroupForm extends yii\base\Model {
public $name;
public $description;
public $date;
public $people = [];
....
}
And visually it will be something similar to this:
I want to be able to use the plus and minus buttons to add additional people to the form. I have the JS in place to actually handle the HTML cloning and such, but I am not sure about how to create the first Person.
I know that I will need the name to be something like Person[0][first_name] but when I instantiate the GroupForm there are no people objects created yet (saved or in memory) so I can't do something like <?php echo $form->field($model->people[0], 'first_name')->textInput(); ?>.
Once the form was submitted I planned on then iterating over all of the 'People' fields in the POST data and loading that into new People objects.
Is it possible to do this with the ActiveForm or is the answer to just not use the ActiveForm and create the inputs using the Html class in Yii and then using JS to change the person index?
Basically what I understood from your post is you need to use dynamic form in your Yii2 project. In your case the form should be containing the group information plus multiple persons to be created along with it. In Yii2 this functionality can be implemented through the usage of wbraganca/yii2-dynamicform form widget.There is very good documentation to how to use the widget with an example scenario.The widget documentation can be found at
https://github.com/wbraganca/yii2-dynamicform
More information and working demos at
http://wbraganca.com/yii2extensions/dynamicform-demo1/create
Hope this helps
I was pushed into an existing CodeIgniter project and am familiarizing myself with the proper conventions for their MVC approach. One thing I'm stuck on is relating models and controllers. The CI documentation gives almost no guidance on this and I'm not sure what the correct approach is. Our project is an API which is called by external applications so I'm not concerned with views, only models and controllers.
This is an off-the-cuff example rather than a practical example, but hopefully it will help me understand: Let's say that I'm making an application that has minigames and a virtual store. The player can earn points by playing minigames. They can spend those points in the shop to buy items. They can also sell items in the shop to earn points. The application should log each transaction of points.
In this situation, my thinking is I would have a:
ShopModel - interacts with the database to load product data and to save what items the user has purchased
MiniGameModel - interacts with the database to load data about the minigames and save scores
PointsModel - interacts with the database to transfer points into or out of the player's account (and writes corresponding log entries in the "log" table)
ShopController - utilizes ShopModel and PointsModel
MiniGameController - utilizes MiniGameModel and PointsModel
So, for example, the user tells the application they want to search the shop for "weapons". The application requests weapons from the controller. The shop controller builds a query and the shop model executes the query and returns the records. The controller formats the records as JSON and sends them back to the application.
The user tells the application they want to buy the shield. The application notifies the shop controller. The shop controller queries the price from the shop model, then tells the points model to subtract the points, then tells the shop model to give the player the shield. Finally, the controller notifies the application via JSON that the shield was purchased.
Is this an acceptable structure, or should each controller only have one model? If there should only be one model per controller, how do I avoid copy-pasting code that handles the points? Am I doing this completely wrong?
Please do not get hung up on the database structure or anything like that. This is not a real example. I'm just trying to figure out how to organize classes.
It's really as simple as you're thinking. Models in Codeigniter are just supposed to passed db results to the controller, or custom class, then to the controller.
You can load as many models as you like in a controller - thats not a problem at all. Personally I try to keep my model > db table in a one to one relationship. If I have work to do on the data from the model, i'll usually add a Library (custom class) to handle that part.
That way my controller stays clean.
i would give you some suggestion :
To save your time use this API RESTSERVER for functionally like you
explain.
For common functionality make a library, then auto load it and when ever you need it just called it where you want.you can called a library every where ,in view,controller,model .
e.g for just an idea, Library which would look like.
<?php if (!defined('BASEPATH')) {
exit('No direct script access allowed');
}
class Menu {
public $ci;
public $table="tblmenu";
public $full_record = array();
function __construct() {
$this->ci = &get_instance();
$this->company_id = $this->ci->session->userdata('company_id');
}
public function get_menu($comp_id = NULL) {
$comp_id = ($comp_id) ? $comp_id : $this->company_id;
$this->ci->db->select()->from($this->table)->where('company_id', $comp_id);
$this->ci->db->where('visible', 1);
$this->ci->db->order_by('id', 'ASC');
$this->full_record = $this->ci->db->get()->result_array();
return $this->full_record;
}
}
Then when you need it :
$this->load->library('menu');//or auto load it .
$this->menu->get_menu();
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.
How can i pull data from different tables(models) into view in yii. actually i done this with loadModel method. but my question is how can we import the rules into the view too. Here comes my scenario
I have a User model and Profile model. The User model contains username and password and Profile model contains userid,name,address etc. so in my profile edit view i need all these data with the rules, username-unique,password,confirm pasword-required, etc., i can implement the required rule to all these, but i dunno how to import the table related rules like unique.
So basically this is a form that takes in two models and displays that data for you to edit and submit.
Simply make the render call to your view and pass both the models. e.g. $this->render('aview', array('model1'=>$model1, 'model2'=>$model2));
Get your view to display the form elements based upon these models.
When you submit simply create new objects for respective models and populate them with the data received. e.g.
$model1 = new model1;
$model1=>id = id; //id received from the form submit.
...............
Once you have the models populated you can call validate() on each of them to figure out if the data is according to your rules. If it is you proceed otherwise you display error. I hope this helps unless I missed something in your question.
I'm new to the MVC pattern but have been trying to grasp it, for example by reading the documentation for the CakePHP framework that I want to try out. However, now I have stumbled upon a scenario that I'm not really sure how to handle.
The web site I'm working on consists of nine fixed pages, that is, there will never exist any other page than those. Each page contains something specific, like the Guest book page holds guest book notes. However, in addition, every page holds a small news box and a short fact box that an admin should be able to edit. From my point of view, those should be considered as models, e.g. NewsPost and ShortFact with belonging controls NewsPostController and ShortFactController. Notice that they are completely unrelated to each other.
Now, my question is, how do I create a single view (web page) containing the guest book notes as well as the news post box and the short fact? Do I:
Set up a unique controller GuestBookController (with an index() action) for the guest book, so that visiting www.domain.com/guest_book lets the index action fetch the latest news post and a random short fact?
Put static pages in /pages/ and in let the PagesController do the fetching?
< Please fill in the proper way here. >
Thanks in advance!
It sounds like you need to look into elements, or else you may be able to embed this into the layout - but its neater to use an element if you ask me, keep the things separate.
http://book.cakephp.org/2.0/en/views.html#elements
These allow you to have create small views that you are able to embed into other views.
You may also need to put some logic into the AppController (remember all other controllers extend the app controller) to load the data required for these views. The beforeRender function should be useful for this - its one of the hook functions cakephp provides, so if you define it on a controller, its always called after the action is finished before the view is rendered.
Something like this in your AppController should help:
function beforeRender() {
$this->dostuff();
}
function doStuff() {
// do what you need to do here - eg: load some data.
$shortfacts = $this->ShortFact->findAll();
$news = $this->NewsPost->findAll();
// news and shortfacts will be available within the $shortfacts and $news variables in the view.
$this->set('shortfacts', $shortfacts);
$this->set('news', $news);
}
If there are models you need in the app controller for use within this doStuff method, then you need to define them within uses at the top of the AppController
class AppController {
var $uses = array('NewsPost', 'ShortFact');
}