How to load Model into a controller in MVC - php

I am working on building a lightweight MVC, mainly for the learning process but I would like it to be good enough to use eventually.
Below is a basic example/demo of how a basic controller might would look, let's assume the URI has been processed and routed to this controller and these 2 methods.
1) I need to get data from database/cache/etc... inside my Model classes, I just need help on how I should load my models into my example controller below, you can see that I have added this below $profileData = $this->model->getProfile($userId) that is just made up and does not exist's, how could I get something like that to work though? Or should I load the model into the class a different way?
2) A lot of pages will require a user to be logged into the site. SHould I process that part below in the controller to check if a user is logged in, example, before building the profile page, check if user is logged in, if not then build a login page instead and add these checks inside of each controller method/page?
/**
* Example Controller
*/
class User_Controller extends Core_Controller {
// domain.com/user/id-53463463
function profile($userId)
{
//GET data from a Model
$profileData = $this->model->getProfile($userId);
$this->view->load('userProfile', $profileData);
}
// domain.com/user/friends/
function friends()
{
//GET data from a Model
$friendsData = $this->model->getFriendlist();
$this->view->load('userFriends', $friendsData);
}
}
core
abstract class Core_Controller {
protected $view;
protected $model;
function __construct(DependencyContainer $dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
}

There are probably tons of ways to accomplish what you are trying.
The "easiest" is probably to just override the constructor and instantiate the model directly.
in User_Controller:
public function __construct(DependencyContainer $dc) {
parent::__construct($dc);
$this->model = new User_Model();
}
I'm guessing that you are looking for something a little more automated though. If you want the Model to have the same name as the controller minus "_Controller", just use get_class($this) in the constructor and use PHP's string functions to parse out what you want. Once you have that in a variable, you can use that variable to instantiate the model:
in Core_Controller:
public function __construct(DependencyContainer $dc) {
$this->view = new Core_View();
// $model_class should be 'User_Model' now
$model_class = str_replace('_Controller', '_Model', get_class($this));
// now instantiate the model
$this->model = new $model_class();
}
I haven't actually worked with any framework that can only have one model associated with each controller (except may CakePHP? I can't remember). With Symfony, the models and controllers are completely decoupled so you can use any model with any controller. You just instantiate the model as need. Symfony use the Doctrine ORM so for example, in a controller action, if you needed a model you would do something like this:
$model = Doctrine::getTable('User');
It might be worthwhile to consider a design more like that in order to promote a decoupled design and I promise that you will want more than one model in some controller at some point.
2.) As far as authentication. Something that seems to be fairly common is to have some sort of setting (whether in a config file or a member variable) that says whether or not the current action needs the user to be authenticated. This is processed each time the action runs (Yii calls these kinds of things filters). If the user needs to be logged in, it stores the page that they are trying to access, and then redirects them to a log in page (you should only ever have to create one). Once they properly authenticate, it will redirect them back to where they were originally heading.

Related

Laravel Service as Controller - working with multiples controllers

I'am a Brazilian developer, so... sorry for my limited English right away.
Well, in fact my problem is more a convention problem because until now I hadn't use services with Laravel (my apps were that simple so far).
I read about it before ask this question, but nothing helped with this specific situation. I'll try to describe in a objective way.
before that, just a comment: I know about the mistake using just controllers in these example. The ask is really about that mistake.
Well, the actual structure is:
abstract class CRUDController extends Controller {
protected function __construct($data, $validatorData) {
// store the data in a attribute
// create with Validator facade the validation and store too
}
abstract protected function createRecord();
protected function create() {
try {
// do the validation and return an Response instance with error messages
// if the data is ok, store in the database with models
// (here's where the magic takes place) in that store!
// to do that, calls the method createRecord (which is abstract)
$this->createRecord();
// return a success message in an Response instance
}
catch(\Exception $e) {
// return an Response instance with error messages
}
}
}
class UserController extends CRUDController {
public function __construct($data) {
parent::__construct($data, [
'rules' => [
// specific user code here
],
'messages' => [
// specific user code here
],
'customAttributes' => [
// specific user code here
]
]);
}
protected function createRecord() {
$user = new UserModel();
// store values here...
$user->save();
return $user;
}
}
// here's the route to consider in that example
Route::post('/user', 'WebsiteController#register');
class WebsiteController extends Controller {
private $request;
public function __construct(Request $request) {
$this->request = $request;
}
public function register() {
$user = new UserController();
$user->create($this->request);
// here's the problem: controller working with another controller
}
}
class UserAPIController extends Controller {
// use here the UserController too
}
and many other classes that extends CRUDController in the same way...
What I want
I want to create a controller (called here as CRUDController) to reuse methods like the pattern says (create, read, update and delete).
To be really objective here I'll use the create method as an example.
With the code above it seems clear the purpose? I think so... all my controllers have that code of validation equal and reusable. That's the thing.
Besides that, I want to my route of website call another controller (UserController) to store new users... but in the same way, I'll create an API that uses the same controller in the same way (with validations etc). That's the purpose of Responses in the CRUDController (I'll read them in the WebSiteController to resolve what to do, like show a view and in the other hand with the API I'll basically return the Response.
My real problem
Convention and pattern. The MVC pattern is broken here. Controller calling another controller is wrong and I know that.
I want to know what thing I should use! Services? Is that right? I see a lot (really) of examples of services but nothing like that, working with models and reusing code, etc. I never use Services but I know how to use, but I don't know if it's right to these cases.
I really hope that someone can help here and sorry once again for the mistakes with the English. Thanks a lot.
You're calling the CRUD controller a controller but it does not behave as an MVC controller. At best it's just a helper class. You could always do this:
abstract class CRUDManager {
//As you had the CRUDController
}
class UserManager extends CRUDManager {
//As you had the UserController
}
In your AppServiceProvider:
public function boot() {
$app->bind(UserManager::class, function ($app) {
return new UserManager(request()->all()); //I guess that's what you need.
});
}
Whenever you need to use it you can do:
public function register(UserManager $user) {
$user->create();
}
Now one thing to point out. It's not a good idea to initialise the request in the constructor. You should use dependency injection in controller methods. I don't even know if the request is available when the controller is being constructed (I know the session is not). The reason why I say this is that the middleware runs after the controller is constructed and therefore the request may be modified when the controller method is called.
Another note: If you did the original solution because you needed to use certain controller methods, then you can just use the corresponding traits (because the controller itself does not really have many method). I'm guessing a trait like ValidatesRequests would be one you'd need to use.
I'll answer my own question. I use a pattern called Repository Pattern to resolve the problem (or I try to use, because it's the first time using this pattern: maybe I don't use in the right way in every steps).
Files structure
Controllers
UserController.php
Models
UserModel.php
Providers
UserRepositoryServiceProvider.php
Repositories
RepositoryInterface.php
Repository.php
User
UserRepositoryInterface.php
UserRepository.php
Traits
InternalResponse.php
With that structure I did what I wanted in my question without working just with controllers.
I create a trait called InternalResponse. That trait contains a few methods that receive a transaction, validate if it's the case and then return a Response (called "internal" in my logic because the controller will read and maybe change the Response before return it in the end).
The Repository class, which is abstract (because another class must extend it to make sense to use. In this case the class UserRepository will extend...), uses the Trait mentioned.
Well, with it in mind, it's possible to know that the UserController uses the UserRepositoryInterface, that provides an object UserRepository: because the UserRepositoryServiceProvider register this with that interface.
I think there's no need to write code here to explain, because the problem is about an pattern, and these words explain well the problem (in the question) and the resolution with this answer here.
I'll write here a conclusion, I mean, the files structure with comments to explain a little bit more, to end the answer.
Conclusion: Files structure with comments
Controllers
UserController.php
// the controller uses dependency injection and call methods of
// UserRepository, read and changes the Response receveid to finally
// create the final Response, like returning a view or the response
// itself (in the case it's an API controller)
Models
UserModel.php
// an normal model
Providers
UserRepositoryServiceProvider.php
// register the UserRepositoryInterface to
// return a UserRepository object
Repositories
RepositoryInterface.php
// the main interface for the Repository
Repository.php
// the main repository. It's an abstract class.
// All the others repositories must extend that class, because
// there's no reason to use a class Repository without an Model
// to access the database... That class share methods like create,
// read, update and delete, and the methods validate and transaction
// too because uses the trait InternalResponse.
User
UserRepositoryInterface.php
// the interface for UserRepository class
UserRepository.php
// that class extend Repository and uses the UserModel
Traits
InternalResponse.php
// trait with methods like validate and transaction. the method
// validate, read and validate the data receveid for the methods
// create and update. and all the CRUD methods uses the method
// transaction to perform the data to the database and return a
// response of that action.
That's what I do and like I said before, I don't know if it's a hundred percent correct in reference to Repository Pattern.
I hope this can help someone else too.
Thanks for all.

Controllers structuring in PHP frameworks

I'm going for an example to make the question easier:
If you are implementing facebook, you want to separate user information from account information, from posts, from from from, that means there will be a model for user, a model for user info, a model for posts, a model for for for.
now if you go to user profile, it loads information from all these models, the question is how would you structure the controllers, of course you need controllers for each model to define it's unique actions, but how do i handle the rendering?
do i make a new controller that takes care of all renderings? or do i just put render profile in the user controller - which means it will have access to other models - or do i put in each controller a rendering of it's own and then combine them together...
or maybe if you have a better approach?
i just do not know the consequences of each approach that i thought of, and i don't know if there is a better approach that i didn't think of.
As others mentioned, you don't need a controller specifically for each model. However, given your Facebook example, it's quite simply done through relationships.
An oversimplification would be:
A User model to hold the user's account information and relationships
class User extends Eloquent {
public function posts() {
return $this->hasMany('posts', 'from_user_id');
}
}
A Post model to hold the content and from/to relationships to User
class Post extends Eloquent {
public function from() {
return $this->belongsTo('user', 'from_user_id');
}
public function to() {
return $this->belongsTo('user', 'to_user_id');
}
}
Then perhaps you'd have UserController load a view like so:
class UserController extends BaseController {
public function index($id) {
$user = User::find($id);
return View::make('user_page', array(
'user' => $user,
'posts' => $user->posts()->with('to')->get()
));
}
}
of course you need controllers for each model to define it's unique actions
No, this is wrong.
Controllers are part of your presentation layer, some might say you need a controller for each view object which is okay but for the model layer, it has nothing to do with the number of controllers you have.
a View is an object that toggles multiple templates and once again this has nothing to do with your controller, rendering is a view responsibility.
to understand it more, take a look here , here and here
those are really useful information to start with.
Wrong answer - controllers are not part of presentation layer - they are part of transport layer. Their task is to react on HTTP request.
Request is dispatched by Router. To proof take a look at Laravel source. Controller is a part of Routing package. When you call for example:
Route::get("/","HomeController");
You are just registering request parameters in RouteCollection. But everything is happening inside Router. Controllers can exist without any kind of view layer.

Method in one controller calling a method in another controller, using MVC

so i have a user controller, that has methods to update profile, etc. In the system i am developing the user would need to post articles, etc. So i am confused with the design of the system. The main logic of creating articles would be housed under the article_model. But how should i call the methods?
I can create a function in the user controller that calls on the article model to create article?
I can call a method in the user controller and create an article controller and the user controller calls the method on the article controller, which in turns call the model for the main logic.
Or just directly call on a article controller that connects to the article model.
I personally feel i need to have a user controller into this system, as logically speaking a user creates article. So which design is perfect in terms of logic and best practices.
You can load multiple models in a controller, you’re not just restricting to the model in the same domain as the controller. So if you need to interface with articles in the users controller, then just load the articles model. As deceze says, you shouldn’t call other controllers in one controller; that definitely goes against MVC conventions.
In your case, any interaction with an article should be in the articles controller though, accessible at a URL like /articles/add.
I actually use codeigniter and they do it this way. If you want to post an article from your user or profile controller you can just make an instance or load your model.
class ProfileController extends BaseController {
public function __construct()
{
$this->load->model('article_model');
}
public function index(){
$this->article_model->post();
}
}
don't call a controller from another controller
you can add link to any view called with the profile that reefers to add article
if you have to call the controller from another you may have a look at codeigniter hmvc
HMVC: an Introduction and Application
Try to use this extension HMVC for CI. It's allow to call controller methods in another controllers. Something like this:
class Dashboard extends MX_Controller{
public $autoload = array();
public function __construct()
{
parent::__construct();
}
public function index()
{
$params = 'some_params';
$data['some_data'] = Modules::run('another_controller/method', $params);
}
}
Where another_controller - simple CI controller, what expand MX_Controller.

Most efficient way to implement a 'logged-in' check with MVC in PHP?

I know questions similar to this have been asked, but I have been searching through the internet and I can't seem to find exactly what I'm looking for.
The most common answer is to put it in the controller. I liked a particular solution from stackoverflow that had a SessionController and NonSessionController, both extending the main controller but with SessionController checking if the user is logged in before the dispatch.
Does this mean that the controller would look something like this?
class SessionController
{
...
function view()
{
//view thread stuff
}
function post()
{
if loggedin then
{
//post thread stuff
}
}
{
In this situation, it looks like NonSessionController is useless, and that model is only used when every action the controller handles is either strictly for users or non-users, unlike this forum example.
So I guess my question is, is the general concept of the controller above the most efficient way of dealing with login checks when using MVC?
I think the idea would be to have one controller which checks the session and login, and one that doesn't.
I would put the login check in the constructor of the session controller so that way every controller which extends it will check the login.
The session controller would look like
class SessionController
{
public function __construct()
{
if ( ! AuthenticationHelper::isLoggedIn() )
{
// User is not logged in
// Do something, maybe a redirect to login page
}
}
}
Then you can just extend that controller like
class HomeController extends SessionController
{
public function __construct()
{
parent::__construct();
}
public function index()
{
print "This page checks login status";
}
}
I would make a component. If you're writing your own MVC framework then this will be interesting to see how you implement this.
But, basically you need a class to check for session state. But, if you tie yourself to extending a class for logged in and a class for logged out I'd feel you have too much duplicate code. I also just personally don't think its very intuitive. I'd probably wind up losing track of whether or not a controller should extend the Session or NotSession.
I'm actually in the process of writing my own MVC framework and have thought about how I would solve this problem a little. I haven't gotten to where I've actually implemented code so it's more a working theory at this point. :)
Have one controller base class. That class has a property that we'll call $components. Let's make this an array and it can hold the name of classes for things you want to do in a lot of controllers, but doesn't really belong in the controller itself.
Since I'm using the Front Controller design pattern before the action requested is invoked I will gather the array of $components and load the appropriate class file for each entry.
As each $component file is being loaded I will dynamically add that component object to the controller properties. So that a component with name Session might refer to a class named SessionComponent and you can access it in your controller by using $this->Session->do_something() or $this->SessionComponent->do_something()
I kind-of-sort-of ripped the idea from CakePHP. I use Cake as my production PHP framework and a lot of my ideas for the custom built framework I'm working on is, obviously, inspired by Cake.
If you are inside your SessionController, then you shouldn't need to check the loggedin variable for every function, you should do that inside the constructor or the router, if you feel confident enough to manipulate. That way if the user is not logged in, the SessionController file and class would not be loaded at all.
Sorry, no english:
base controller
class Controller{
function handleLogin()
{
if(!Authentication::isLoggedIn())
{
//do stuff - redirect to login page?
}
}
}
someController
class someController extends Controller{
function someAction()
{
//check login
$this->handleLogin();
//do someAction stuff
}
}

Zend Controller

i have created a controller in which the default index action is being used to display a login form and then authenticate the user. However i have ended up having to add functions into the controller which i feel will clutter up the controller.
for example i have functions like:
protected function _process($values)
{
// Get our authentication adapter and check credentials
$adapter = $this->_getAuthAdapter();
$adapter->setIdentity($values['username']);
$adapter->setCredential($values['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
$user = $adapter->getResultRowObject();
$auth->getStorage()->write($user);
return true;
}
return false;
}
protected function _getAuthAdapter() {
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
->setCredentialTreatment('SHA1(CONCAT(?,salt))');
return $authAdapter;
}
What would you recommend to do, maybe create another directory called custom_classes and include the file into my controller this way?
Given your example I would put this into some sort of ACL centered Zend_Controller_Plugin class and register this class in your bootstrap to ensure it is always run.
Also, depending on what you are doing, the logic could go into one of your Models.
Models should represent a collection of information that make up an entity of some sort, the Model class should also be responsible for reading, updating, removing and adding new Models.
For example a User Model could represent a User in a table in your database. It might contain functions like updateFailedLogins(), updateLogins() and specific functions related to the log in process for that particular User Model.
If the methods you add are necessary for the controller to handle the input it receives from the User Interface, then it's fine to have them there. If it's a different concern, identify which responsibility it is and add the method there.
If you find the logic in the methods is useful in many controllers, consider making the logic into a Zend_Controller_Action_Helper. If you find this is that has to run on every request but is not directly related to a Controller Action, make it into a Zend_Controller_Plugin.
In case of authenticating users, you might want to create a Zend_Controller_Plugin that authenticates the user before the actual Controller Action is called.

Categories