MVC in yii: how to build pages with several actions belonging to different models - model-view-controller

I would like to know how you should write website pages that use for example 3 models and several actions on them.
Because there is usually only a controller involved with a page call and only a special action.
For example:
there should be a page which displays a group of people, and on that page I can edit the peoples names and assign new people to the group and i can add people as new managers of a group.
Does this page need its own controller or how do I program such pages?

Using your scenario, here is how I would set things up:
The controller you'd use for all related actions would be 'Group' (in Yii, 'ControllerGroup')
For your main page that displays the group of people, you could make an action in your Group controller called 'manage' (in Yii, the method name would be actionManage). Assuming you aren't going an Ajax route, for each person on the manage page you may have a link to edit that person. The links would point to the 'update' action. For adding, you'd want an action 'add'.
Your models involved would likely be User, Group, and UserGroup and you'd use them as necessary in any controller you have.

Actions can belong only to controllers. In each action you can work with any models of your application. In your case you must create a UserController and a list of actions (e.g. actionViewList, actionEdit, actionAssignToGroup).
Check this for more information: Yii Controller

Related

What pattern or architecture should I implement by Laravel to structure this project?

The project is simple, and it has to do with formula 1 statistics. The UI looks a lot like a game menu. Going from "option" to "option" in the UI you end up in an "endpoint" page where the user can see the statistics of his like. It's tree structure where every "option" is a separate view on my project.
The user click "Race standings" to load a page. The user click a year on a form to see next page. The user click a race of that year then redirects to "race result" page. The logic for doing this is to create a nice UI so the user would like to spend time on the site and navigate through the pages.
I POST data from my view's forms to a controller's function. This function fetch the data from the database using my models and the post parameters, do the logic and return('thatView', compact('array' , 'array2', 'etc). php and javascript on the views manipulates the organized arrays fitting them into html. Arrays contains text data, for example array 1 could be the data of a race-result table.
The way my project is structure is very amateur. No patterns, no architecture, no anything good. Using directly the raceresult domain on the browser will result error. The needed parameters are missing as they cannot be set from the domain, it needs the previous page to post the data.
How could i structure my project better? What patterns could i use?
This is a basic overview you can follow:
App
-- Repositories
-- Services
Route > Controller > Service > Repository
Controller's method calls Service method. Here you put your business rules. If there as need of calling database, use repositories to do that.
It's clear for you?

Convention for a controller that generates a view from several models

In Sails.js, a route is set up against a controller method which can render a view. For the most part, this is straightforward, i.e. you could set up a GET /users route that points to UserController.find (which is usually set up automatically anyway).
However, say the home page of a blog renders the 10 most recent posts in the main section and a column with a list of authors and categories. The controller method has to fetch posts, authors, and categories before rendering the view and sending it back to the client. Clearly, a method like this doesn't really belong in PostController, AuthorController, or CategoryController.
What's the best thing to do in this situation? Create a controller for rendering views that rely on data from multiple models? Is there a good name for such a controller?
Thanks!
What I would do (this is purely opinion-based) is creating a PageController and create an action for each page you'd want.
For your home page example you can create a home action, get whatever you need and then render it with res.ok() (if everything is fine).
Another option would be to use Sails as a pure API and use HTTP requests (Ajax) or sockets to get your data in JSON. If you want to do so, I'd advise you to use a front end framework such as Angular, Ember, React...
By the way you could also create actions rendering HTML in your existing controllers and create a route to hit them through Ajax requests and just print them in your page. I'd prefer the 2nd solution because it takes full advantage of the Blueprint API (you don't need new controller or action whatsoever).
As Yann pointed out, this answer has to be a little opinionated. It seems that you are using the views system and not building a single page application. For the home page, I would go for an IndexController.js file with a home(req, res) action.
// api/controllers/IndexController.js
module.exports = {
home: function (req, res) {
// Retrieve all the information you need
// Take care about managing the asynchronous calls before rendering the view
return res.view('homepage');
}
};
Declare the route
// config/routes.js
module.exports.routes = {
'get /': 'IndexController.home'
}
Create the view in views/homepage.ejs.

CakePHP - Render views using elements vs ajax

If views from different controllers use the same element, requiring different controllers to pass the same datas (hence maybe doing the same processing) to the views, wouldn't it be better to make an AJAX call to a single controller?
Let's say we have this:
Model/Post.php
Model/User.php
Model/Service.php
Controllers/UsersController.php
Controllers/ServicesController.php
Views/Users/view.ctp
Views/Services/view.ctp
Views/Elements/list_users_post.ctp
A user belongs to a service, and a user has many posts.
In Views/Services/view.ctp, I want to display a list of each user of a particular service, and for each user, some related infos and a list of his 10 last posts.
In Views/Users/view.ctp, I want to display user's related infos and a list of his 10 lasts posts.
The element Views/Elements/list_users_post.ctp allows me to factor the code displaying a table of a user's posts. It needs the var $userPostList to be set, and to be structured the same as the result of $this->Post->find('all', array('conditions' => array('user_id' => $userId))).
So in my UsersController::view($userId) and ServicesController::view($serviceId) actions, I end up with some duplicated code retrieving users' posts.
I thought to refactor the code so the action ServicesController::view($serviceId) don't make any find on Post model, but instead, the view Services/index.ctp makes AJAX calls to the action UsersController::view($userId) for each user. That way, no more duplicated code, but with the overhead of AJAX calls.
Any thoughts?
A good way to avoid duplicate code in your case is to move it to the model layer. So instead of this in the controller:
$this->Post->find('all', array('conditions' => array('user_id' => $userId)))
You would have this in the controllers:
$this->Post->getUserPosts($userId);
And this in the Post model:
function getUserPosts($userId){
return $this->find('all', array('conditions' => array('user_id' => $userId)));
}
AJAX calls are also a good solution but even with them it would be best to keep the business logic in the models if possible.
Other ways to avoid duplicate code include(but are not limited to):
Using Helpers in Views
Using Components in Controllers
Using Behaviors in Models
That should get you started on keeping your code DRY.

MVC3 Routing - Routes that builds on each other

I have an AREA setup in my project. I need to make the routes for the area progressive, meaning that the route will build on each other.
I'm looking at this as something like a link list. Each node in the list will have a reference to a parent. As move from left to right in the list it builds, and from right to left it removes.
In the area, I have companies and that have contacts, and child companies.
For example, I have companies that would have the following:
/Companies/list
/Company/{Id}
/Company/{id}/add
/Company/{id}/edit
/Company/{id}/delete
For the contact section I need to create the following routes:
/Company/{id}/contacts/list
/Company/{id}/contact/{id}/add
/Company/{id}/contact/{id}/edit
/Company/{id}/contact/{id}/delete
How do I make sure that /Company/{id} is always in the Contact and Child Company sections of the route?
I hope that I have made my question clear.
Subjective Generalities (take with a pinch of salt):
First off, you are using Company (singular) for companies, but then you are using contacts (plural) for the contacts. There is nothing wrong with this, from a structural point of view, but your users will thank you if you are consistent with your pluralizations. I would use the plural in both cases, but that is just my preference... it looks more like English.
You also use lower case for contacts, but upper case for Company. Doesn't look professional.
The next thing that is confusing is that you are using two {id} parameters, one for companies, one for contacts. I presume these are the ids for Company and Contacts respectively. But I am confused, but being human, I am able to deduce context unlike a computer. So you would be better of specifying the parameters in your routes. Ie:
/Companies/{CompanyId}/Contacts/{ContactId}/[action]
Answering your Question with an Example:
I get the feel you don't understand routes properly. If you did, your question would be more specific.
Your route parameters can come from a number of sources, depending on how the route is requested.
You could hard code it into a link. Or, more usefully, your route registration would be designed to catch requests that map to your Action signatures.
For example, I have an eLearning app with tutors, pupils, courses and steps (ie, the steps are like sections of a course, the pupil advances through the course step by step)
The route registration looks something like:
Route or Area Registration:
context.MapRoute(
"StepDisplay",
"Course/{CourseId}/Step/{StepOrder}/Pupil/{PupilName}/{TutorName}",
new { controller = "Course", action = "Display", TutorName = UrlParameter.Optional },
new[] { "ES.eLearningFE.Areas.Courses.Controllers" }
);
This route will catch a request from the following ActionLink:
ActionLink in View:
#Html.ActionLink(#StepTitle, MVC.Courses.Course.Actions.Display(Model.CourseId, step.StepOrder, Model.Pupil.UserName, tutorName))
Now, I just need to show you the Display action's signature:
CoursesController:
public virtual ActionResult Display(int CourseId, int StepOrder, string PupilName, string TutorName)
There are a few things to note here:
That I am able to call this specific route by giving the user a link to click on.
I construct this link using the Html.ActionLink helper
I have used David Ebbo's t4mvc nuget package so that I can specify the action I am calling and its parameters. By which I mean specifying the ActionResult parameter of the Html.ActionLink helper using:
MVC.Courses.Course.Actions.Display(Model.CourseId, step.StepOrder, Model.Pupil.UserName, tutorName)
If you think about it, what routes do is translate the url of a request into an action, so the parameters of my route are either the controller name, the action name or else they are the names of parameters in the action signature.
You can see now why naming two distinct route parameters with the same
name is such a bad idea (largely because it won't work).
So, look at your action signatures, and design your routes and your action links so that the everything marries up together.
MVC doesn't work by magic!! (Although the way it uses name conventions might lead you to believe it)

Codeigniter - reusing controllers?

I am trying to code my first codeigniter project. I have a login controller which basically filters the data inputed and calls a model function that checks if the user is found in the database.
What I am trying to do is reuse this controller on the index page. So basically I want to be able to do user login on the index page or on the normal controller page (index.php/login/) without code duplication.
I'm sure there is an easy way to do this, but I'm not sure what the best solution is. Make it a library?
Thanks!
For this I would simply make the form in your view post to the login controller.
As a more generic way to share code and logic throughout your application, take a look at this article:
CodeIgniter Base Classes: Keeping it DRY
You basically give each of your controllers a "type". Being logged in could be a criteria of one of your base controllers, which saves you trying to directly access any of your controllers which is bad mojo.
You can try creating a form on the index page and submit it to index.php/login/. This way you won't need two entry points.
Just do the same as you have done for the login View, specify the same action attribute of the form to the index View, and it will be sent to the same login controller with no need to create the two login controllers. You might want to append a query string in the action attribute of the form to distinguish from which View the request has come.

Resources