I'm little bit confused. I want to build my own framework just to learn how everything works not that I will use it for big projects.
I have a FrontController class and this class has the route functionality inside.
Functions to set/get Parameters for Controller
Functions to set/get Actions (methods) from Controller
Functions to parse the requested URI and return proper controller if exists if not returns default controller which is IndexController.
Run() method that does the following:
public function run() {
$method = new \ReflectionMethod($this->controller, $this->action);
$numParams = $method->getNumberOfParameters();
//fill missing parameters with null values
if (count($this->params) != $numParams) {
$tempArray = array_fill(0, $numParams, null);
$this->setParams($this->params + $tempArray);
}
$controller = new $this->controller;
$userInstance = User::getInstance();
//just creates a model based on the controller name by default its
//Index.php (model)
$model = DB::createModel($this->getControllerName());
//run _before before any function
$controller->_before($model, $userInstance);
call_user_func_array(array($controller, $this->action), $this->params);
return;
}
now I've seen tutorials and they use BaseController and each Controller then extends from this basecontroller. My controllers do not extend from FrontController.
My question is Do i need a separate class for Routing? DO i need to split FrontController into
BaseController
Route.php
Model.php
Since run() function actually passes the model and user object to the controller.
One basic principle to keep in mind is the Single Responsibility Principle. A well designed class has exactly one responsibility.
So yes. You will need to separate the routing and all other responsibilities.
Also note that the model must be considered a layer and not a class or object. The model layer is a collection of classes (data access, services). In fact, your User class should be considered part of that layer.
Here's an article which can help you understand the MVC pattern a bit better.
Related
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.
I'm building a MVC PHP framework from scratch, and I have some problems regarding the model layer.
What I have right now is a relatively basic MVC implementation, here's my entry point ( index.php ):
//get the URI
$uri = isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/';
//Initializes the request abstraction from URI
$request = new request($uri);
//getting the view class from the request
$viewFactory = new viewFactory();
$view = $viewFactory->getView($request);
$view->setDefaultTemplateLocation(__DIR__ . '/templates');
//getting the data mapper from the connection string
$connectionString = "mysql:host=localhost;dbname=test;username=root;";
$dataMapperFactory = new dataMapperFactory($connectionString);
$dataMapper = $dataMapperFactory->getDataMapper();
$modelFactory = new modelFactory($dataMapper);
//getting controller and feeding it the view, the request and the modelFactory.
$controllerFactory = new controllerFactory();
$controller = $controllerFactory->getController($request,$view,$modelFactory);
//Execute the necessary command on the controller
$command = $request->getCommand();
$controller->{$command}($request);
//Produces the response
echo $view->render();
I think this is self explanatory, but if you don't get something, or if you think I did some horrible mistake, feel free to tell me.
Anyway, the modelFactory is in charge of returning whatever model the controller could require. I now need to implement the "model research" logic, and in my opinion there's two ways of doing it:
First way: Implementing a modelSearch class containing all research logic, then make my model inheriting it ( like in Yii2 ). I don't like this method because it would make me instantiate some model and have it returning other instance of itself. So I have the same model instantiated once to research and once ( or more ) with all datas, and no use of search methods.
so my controller would look like that:
class site extends controller{
public function __construct($view, $modelFactory){
parent::__construct($view, $modelFactory);
/* code here */
}
public function index()
{
$searchModel = $this->modelFactory->buildModel("exemple");
$model = $searchModel->get(["id"=>3])->one();
$this->render('index',['model' => $model]);
}
}
Second way: Implementing a modelSearch class containing all research logic, then in the entry point, instead of instantiating the modelFactory, I could istantiate the modelSearch, and feeding it the dataMapper. Then I give the modelSearch to the controller, and the controller would get any model he wants by asking the modelSearch ( which would use the modelFactory to instantiate models and return them ), like that:
class site extends controller{
public function __construct($view, $searchModel){
parent::__construct($view, $searchModel);
}
public function index()
{
$model = $this->searchModel->get("exemple",["id"=>3])->one();
$this->render('index',['model' => $model]);
}
}
This way seems more correct to me, but has the disadvantage of having to call the modelSearch class to return any model, even empty ones.
Thoughts?
TL;DR: modelSearch: Do I use it as independant tool to get models, or do I make models inherit from it?
Searching logic should be within the model itself as the MVC describes model,view & controller. Model should have only one responsibilities that is work with database itself. While as controller should be responsible for manipulating of data and passing the data.
First read any MVC pattern PHP framework as CI, CakePHP and YII, and then you will see the model (how it works with database). and you can create there self model searching logic and you can see YII framework for best searching logic in model and usability in controllers.
My goal of asking this question is to ferret out whether there are benefits to injecting Controller directly with the data it needs (more specific approach) opposed to injecting a Model into a Controller (more generic approach). Or to establish whether or not it is just a matter of preference.
Injecting Controller with Model:
Model can be used to run all kinds of queries to retrieve various bits of data, but it is a heavier-weight construct than the data itself. Model essentially contains data, or at least it can access all the data you may need. Example:
class CategoryControllerWithModel
{
private $model;
public function __construct($model)
{
$this->model = $model;
}
// generates HTML for input form
public function genHtml()
{
/* retrieve data */
$categories = $this->model->getCategories();
//...
}
}
//instantiation within Factory Method:
class Factory
{
$model = new CategoryModel();
$controller = new CategoryControllerWithModel($model);
return $controller;
}
Injecting Controller with Data:
Here we do a bit more upfront with in the Factory method but we get a leaner Controller that only receives exactly the data it needs and is so completely separated from the Model that it is not even aware of its existence.
class CategoryControllerWithData
{
private $categories;
public function __construct($categories)
{
$this->categories = $categories;
}
public function genHtml()
{
$categories = $this->categories;
}
}
//instantiation within Factory Method:
class Factory
{
$model = new CategoryModel();
//a bit more work to get the data Controller needs
//benefit: Controller not tied to the Model
$categories = $model->getCategories():
$controller = new CategoryControllerWithData($categories);
return $controller;
}
Question:
I suppose MVC stands for exactly that -- Model, View, Controller, so injecting Model is probably considered to be an "okay" thing to do. If so, am I taking this too far by trying to remove Controller dependency on Model?
Suppose I insist that I want to inject Data into my Controllers rather than the Model. Is this a purely preferential issue do you see any concrete benefits of doing so?
From my point of view, Factory shouldn't be responsible for domain logic. It should only be responsible for building things up.
In this case, where you are injecting data, Factory has to know what categories controller is searching for, are there any filtering and so on.
So I think for controller you should only inject model, keep Factory single responsibility only for building things and controller should be responsible for it's data.
I think it's a matter of "separation of concerns" also I do not think that would be a good example of using MVC. I would think more along these lines:
class FooController
{
public function actionView($alias){
$category = Category::loadByAlias($alias);
..... load and render layouts etc .....
}
public function actionList(){
$categories = Category::loadAll();
..... etc ......
}
}
like this the neither the Controller nor the Factory need to know what needs to be done when you load a category nor do they have to handle active/inactive status, even User access ... etc this is all Model Logic, Model can have beforeLoad and afterLoad functions, conditions for listing all categories, eager or lazy loading of related models etc...
I'm building a simple MVC framework in PHP and I'm stuck at the part where I have to create a BaseController class.
Every "page" controller needs to extend from this BaseController. Because this BaseController class will have properties that will give the user access to a template engine and a Logger class (and some other things).
The problem I have is that I'm not sure how to instantiate those things in the BaseController class. I can obviously hard code it in the __constructo() like this:
class BaseController
{
protected $view;
protected $log;
public function __construct()
{
$this->view = new \namespace\view('param1', 'param2');
$this->log = new Logger('name');
$this->log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
}
}
But this doesn't make it very modular. It makes it hard to change the Logger class for example. Or if the user wants to change the template engine to Smarty for example.
I also can't really use a form of Dependancy Injection. Because then every controller that extends from the BaseController will have to pass those instances to the BaseController.
That would look something like this:
class BaseController
{
protected $view;
protected $log;
public function __construct($view, $log)
{
$this->view = $view;
$this->log = $log;
}
}
HomeController
class HomeController extends BaseController
{
public function __construct($view, $log)
{
parent::__construct($view, $log);
// Do my own stuff
}
}
To me that's not really user friendly when a user only wants to do a simple thing in the __constructor. Not even with an IoC.
So the only thing that I can think of now is to use a Service Provider from the __construct method in the BaseController. But I'm not really sure if that's the way to go? Maybe there is a better alternative?
So what would be a good solution to solve this problem?
PS. And if I do need a Service Locator, are there any good examples out there? The ones I've found were written by people that seemed like they didn't really know what they were talking about. They were basically copying each others blog posts.
You first need to think what's a controllers responsibility, why would it need access to logging functionality or why would it be setting the template engine or switching templates?
The controllers job is simply to extract the data from the request(mostly form data/user input) and sending it to the model layer via a service, it should not be selecting templates, that's the views job.
You obviously want you keep the dependencies of your base controller to a minimum so that when instantiating child controllers you don't have a big list of dependencies to inject.
My base controller has two dependencies, the request object and a view which are both injected in. Controllers are simple and light, no logic or anything fancy should happen in them. Once ever I had to use a logger in one of my controllers but that was just because PayPal was sending a request to it using the IPN system and I needed to log all the data in the request to a file to see what was going on, other than special cases like that I can't see why a controller would need a logger. In this case only the controller which dealt with the PayPal request held an instance of a logger, not the parent base controller.
You should always inject your dependencies. Don't instantiate objects in constructors, it makes your class tightly coupled to those objects.
If you end up using a service locator it can be a sign that your classes break the single responsibility principle of OOP.
Controllers are meant to be simple, don't over complicate them by adding in dependencies you think they might need in the future, especially not to the base controller or you may have a lot of refactoring to do.
Just a quick logical question.
I have 2 Zend Controllers namely Merchant and Account. Merchant Controller has an action called editAction. My question is whether it is possible to have same action in Account as well without duplicating the code. I managed to create a include file for the view but I like to have a best way to manage my code. I currently have an idea of having an Helper class and invoke that helper class to both these Controllers. But I know someone would have got better solution than this. Please help me.
Thank you
The simplest solution would be to extend Zend_Controller_Action into your own base class and put editAction() into that. For example, assuming you have model classes named 'Account' and 'Merchant':
abstract class My_Controller_Action extends Zend_Controller_Action
{
protected $_modelName;
public function editAction()
{
$model = new $this->_modelName();
// Do your editing here.
}
}
class AccountController extends My_Controller_Action
{
protected $_modelName = 'Account';
}
class MerchantController extends My_Controller_Action
{
protected $_modelName = 'Merchant';
}
Keep in mind that this design implies that the code in editAction() would work for both Accounts and Merchants.
I think the best course of action would be to put majority of the logic inside your Models and keep your controllers lean. Your models can extend your own class which would have common operations in it.
You could also write your own class, it doesn't have to be a helper, and use it in the controllers to save the entity:
$saver = new My_Editing_Class();
$saver->edit("account",$this->getRequest()->getPost()); // Editing "account" with the POST data.
You then do your magic inside "My_Editing_Class".