I have a model named Message, which is an internal notification in my website.
I have a controller, RegistrationController that handles when a new person registers with my website. When this happens I send a Message to all users.
This is how the code involved looks like:
public static createMessage($receiver, $content)
{
$message = new Message;
$message->receiver = $receiver;
$message->content = $content;
$message->save(false);
}
It is called like this in the RegistrationController.php
foreach($users as user)
Message::createMessage($user->ID, $content);
What is the best approach and that it won't violate mvc?
Inside the Message model I add the createMessage() function. It doesn't require imports.
Or I create a MessageController and add that function inside? If I do version 2 then I need to include MessageController in the RegistrationController.
Any better idea.
Which version would produce better code that can better be maintained? Please quantify your answer to avoid opinions.
Doing MVC is a style of programming.
There is no restriction where to put a logic. You can put it in Models or Controllers.
Which ever best suit your work style, use it.
I usually put in Controller the logics that interact with users through interfaces. (Get values from interfaces)
And put in Models the logics that help business rules. (Do things with the value from interface and database)
If you decide to put your Message logic as Controller, you do not need to include MessageController.
But make sure in the /config/main.php you include this:
'application.controllers.*'
Related
Since my app is getting bigger i would like to separate admin prefix actions and views from normal actions and views. The new folder for admin is Controller/admin/UsersController.php.
I would like to change my cakephp controllers and views folder structure to match the prefix I'm using.
Example for admin prefix:
Controller:
app/Controller/UsersController.php (contain view(), index() ...)
app/Controller/admin/UsersController.php (contain admin_view(), admin_index() ...)
View:
app/View/Users/index.ctp (for index() in UsersController.php)
app/View/Users/admin/index.ctp (for admin_index() in admin/UsersController.php)
How can I implement this structure using Cakephp 2.6?
Unlike in 3.x where this is the default behavior for prefixes, this isn't supported in 2.x.
You could try hacking it in using a custom/extended dispatcher (in order to retrieve the desired controller) or even dispatcher filters in case you are adventurous, and in your app controller modify the view template path with respect to the prefix.
That should do it, however I would probably simply go for using plugins instead, this will separate things just fine without any additional fiddling.
If you just want to separate logic you could do something like this. It's untested an just thought to give you just the idea. I'll explain the concept after the code:
public function beforeFilter() {
if ($this->request->prefix === 'foo') {
$name = Inflector::classify($this->request->prefix);
$className = $name . 'ChildController';
App::uses($className, 'Controller/Foo');
$this->ChildController = new $className($this);
}
}
public function __call($method, $args) {
if ($this->request->prefix === 'foo' && method_exists($this->ChildController, $method)) {
call_user_func_array([$this->ChildController, $method], $args);
}
}
Depending on the prefix you can load other classes. How you load that class and how you instantiate it, what params you pass to it is up to you. In my example I'm passing the controller instance directly. I think you could actually init a complete controller here but be aware that components like the Session might cause a problem because they might have been already initiated by the "parent" controller.
When you now call a controller method that doesn't exist it will try to call the same method with the same arguments on the ChildController. Not really a great name for it, but maybe you can come up with something better.
You'll have to implement some logic to load the views from the right place in your classes as well but this shouldn't be hard, just check the controller class.
But actually I don't see your problem, I've worked on an app that hat over 560 tables and not putting the code into sub folders wasn't a problem, it did in fact use a similar solution.
I think you have to much code in your controllers, get more code into your models and the controller shouldn't be a problem.
Another solution might be to think about implementing a service layer in CakePHP which implements the actual business logic while a model is reduced to a data handler. The service would sit between a controller and the model. I've done this a few times as well now and if done right it works very well.
I'm trying to decide on something, where to put database logic, in the controller or model when using the eloquent orm.
In a controller I have the following method:
public function postAdd(){
$amodel=new myModel();
$amodel->name=Input::get('name');
$amodel->save();
$id=$amodel->id;
}
Which is how the guides say to use it however should this logic not go inside a method on the model rather than in the controller? I know the above still provides abstraction from the database but the bit that I'm unsure of is how reusable it then becomes... or not as the case maybe.
Would it therefore be a better option to do the following:
public function postAdd(){
$amodel=new myModel();
$id = $amodel->addPost(Input::get('name'));
}
So I pass along information to a method on the model which does the work. This allows it to be reused and the model method changed if required without updating many lines of code?
The answer might simply be 'yes, do it like you've suggested' in which case great but I'd be interested on the standard practice when using an ORM like this.
A controller's sole responsibility is handling and delegating UI requests to the Model. That's why it should be skinny. It should only contain code necessary for what it's responsible for. So thats why you should move your code to the model, or, even better and more Laravel-like solution is to use repositories in this case. (link)
I have created a login system and I am trying to stick to the rules of MVC as much as possible.
I have a simple login form that uses AJAX to submit the form data to small script, which then calls the controller for the processing of the username and password:
function __autoload($classname) {
include("../classes/$classname.php");
}
$username = $_POST['username'] ;
$password = $_POST['password'] ;
$AC = new AccessControl ;
$result = $AC->login($username, $password) ;
if($result !== 0)
{
echo $result ;
exit() ;
}
AccessControl is my class for user authentication and account management operations, the code is here in my other post: MVC Relationships and DRY
Have I done this wrong because this small script isn't a controller or a model? All it does is relay information returned from the controller back to the interface/view, such as error messages.
First, don't let any particular paradigm prevent you from doing things the best way possible in your particular situation.
That said, your small script is a controller. It's processing an action and returning a result. It may not be managing a specific view but it's delegating processing and handing off the result to a view.
In my oppinion, haven't used the MVC structre to the blood, this is about right, with some minor changings.
I usually prefeer something like :
$AC = new AccessControl ;
$AC->setUsername($_POST['username']);
$AC->setPassword($_POST['password']);
if ( $AC->login() )
echo $result // if all is ok from login method return true
else
// manage some error handling here if not true
Maybe you want to user that Username and Password in more places and other methods, so you can use getPassword() / getUsername()
You are mixing authentication and authorization. Structures like AccessControl should be dealing with authorization, not authentication .. you choice of names .. emm ... leaves room for improvement. To learn more about the authorization in context of MVC, i would recommend to read this post.
Authentication, in context of MVC and MVC inspired design patterns, should be part of the model layer and handled by some form of Recognition service.
What you have on the code snipper looks a bot like code from controller's method, but it has several issues.
Ok .. lets pike apart to code:
The use of __autoload() function is not recommended. You should instead learn how to utilize spl_autoload_register() function. It would let you code to use multiple leaders.
Also, since release of 5.3, it is possible to use namespaces in PHP. In combination with autoloaders, it would let you better organize you code. Lately it is common practices to map project directory structures (at least partially) to namespaces.
The most known implementation would be PSR-0, though it should not be considered even close to ideal. It has some serious flaws, but it will make for a good example to illustrate use of namespaces in autoloading.
You should avoid use of new deep in the application call graph. This causes tight coupling to the name of class from which you are creating the new instance.
Instead your controller should have a factory injected into constructor, which then is responsible for initialization of new instances.
namespace Controller;
class Foo
{
protected $serviceFactory = null;
protected $view = null;
// --- SNIP ---
public function __construct( HasSomeFactoryInterface $factory, $view )
{
$this->serviceFactory = $factory;
$this->view = $view;
}
public function postLogin( $request )
{
$recognition = $this->serviceFactory->create('AccessControl');
// --- SNIP ---
}
Controller in MVC design pattern should only change the state of model layer and current view. It does not return anything nor passes data from model layer to view. You seem to confuse classical MVC, Model2 MVC, MVP, MVVP and the Rails parody of MVC pattern.
In the Model2 MVC (also known as Web MVC) design pattern the controller take the incoming user request, and, by passing data from said request to the respective parts of triad, changes their state.
namespace Controller;
class Foo
{
// --- SNIP ---
public function postLogin( $request )
{
$recognition = $this->serviceFactory->create('AccessControl');
$recognition->login( $request->getPost( 'username' ),
$request->getPost( 'password' ) );
$this->view->prepare( $request->getMethod() );
}
// --- SNIP ---
}
In this example view receives notification, that the POST request was received, which means, that, instead of generating HTML from several of templates, it has to only send HTTP header as a response.
To see a short overview about the MVC-related patterns, try this post.
If you are aiming for Model2 MVC design pattern, then view should retrieve information from model layer on its own. But all MVC-inspired design patterns view is supposed to be responsible for the presentation logic.
That also includes dealing with error state in model layer. Domain business logic has nothing to do with how view represents errors.
I know extending a class with the same name is not possible, but I was curious if anyone knew of a way to load a class then rename it, so i can later extend it with the original name. Hopefully like something below:
<?php
//function to load and rename Class1 to Class2: does something like this exist?
load_and_rename_class('Class1', 'Class2');
//now i can extend the renamed class and use the original name:
class Class1 extends Class2{
}
?>
EDIT:
Well, I understand that this would be terrible practice in a basic OOP environment where there are large libraries of class files. But i'm using the CakePHP MVC framework and it would make great sense to be able to extend plugin classes in this way since the framework follows a well established naming convention (Model names, view names, controller names, url routes (http://site.com/users), etc).
As of now, to extend a CakePHP plugin (eg: Users plugin) you have to extend all the model, view, and controller classes each with different names by adding a prefix (like AppUsers) then do some more coding to rename the variable names, then you have to code the renamed url routes, etc. etc. to ultimately get back to a 'Users' name convention.
Since the MVC framework code is well organized it would easily make sense in the code if something like the above is able to be implemented.
I'm trying to work out why this would be necessary. I can only think of the following example:
In a context that you have no control over, an object is initialised:
// A class you can't change
class ImmutableClass {
private function __construct() {
$this->myObject = new AnotherImmutableClass();
}
}
$immutable = new ImmutableClass();
// And now you want to call a custom, currently non existing method on myObject
// Because for some reason you need the context that this instance provides
$immutable->myObject->yourCustomMethod();
And so now you want to add methods to AnotherImmutableClass without editing either Immutable class.
This is absolutely impossible.
All you can do from that context is to wrap that object in a decorator, or run a helper function, passing the object.
// Helper function
doSomethingToMyObject($immutable->myObject);
// Or decorator method
$myDecoratedObject = new objectDecorator($immutable->myObject);
$myDecoratedObject->doSomethingToMyObject();
Sorry if I got the wrong end of the stick.
For more information on decorators see this question:
how to implement a decorator in PHP?.
I happen to understand why you would want to do this, and have come up with a way to accomplish what the end goal is. For everyone else, this is an example of what the author may be dealing with...
Through out a CakePHP application you may have references to helper classes (as an example > $this->Form->input();)
Then at some point you may want to add something to that input() function, but still use the Form class name, because it is through out your application. At the same time though you don't want to rewrite the entire Form class, and instead just update small pieces of it. So given that requirement, the way to accomplish it is this...
You do have to copy the existing class out of the Cake core, but you do NOT make any changes to it, and then when ever you upgrade cake you simply make an exact copy to this new directory. (For example copy lib/Cake/View/Helper/FormHelper.php to app/View/Helper/CakeFormHelper.php)
You can then add a new file called app/View/Helper/FormHelper.php and have that FormHelper extend CakeFormHelper, ie.
App::uses('CakeFormHelper', 'View/Helper');
FormHelper extends CakeFormHelper {
// over write the individual pieces of the class here
}
For projects written in php, can I call more than one (or multiple) controller in class controller? Example in http://img192.imageshack.us/img192/7538/mvc03.gif
ASK: I need to call an action from another controller... And if I do like the picture above, I'm being out-ethics?
Thanks,
Vinicius.
I'm sure that you can do what you want with whichever framework you're using. If you can't do it natively for whatever reason, then you can extend your framework as required.
Having said that, I personally don't like the idea of a controller calling another controller. It seems to somewhat break the MVC paradigm if only from a theoretical standpoint. What I might do instead is build a library class that contains the functionality required and then have both controllers instantiate that class as a member and call the functions required.
For example, using CodeIgniter:
libraries/MyLib.php:
class MyLib
{
public function MyFunc()
{ /* do whatever */ }
}
controllers/ControllerA.php:
class ControllerA extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
controllers/ControllerB:
class ControllerB extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
out-ethics? Anywhose... back to reality.
Yes, a controller can call another controller's action. For instance, in cakePHP, this functionality is afforded via requestAction
// pass uri to request action and receive vars back
$ot3 = $this->requestAction('/stories/xenu');
If you're rolling your own, the details of how to implement it will be very specific to your framework.
then you need to modify framework, find place where controller is lounched and add there your second controller.
what framework you are using?
You can do it any way that you want. You don't have to use MVC if you don't want to. However, in MVC you really should only have one controller active at a time. You probably want multiple Views or Models, not another Controller. There is nothing at all wrong in loading, say, a header and footer view for the menu and footer of the site.
If you are building another Controller, then feel that you need to access the functionality of a previous Controller to access its functionality (because it works with a specific / desired Model), then the Model you developed for the latter probably needs to be refactored. IN plain speak, your target Model may be doing too much. Break it up.
You are trying to avoid repeating yourself (DRY) by using calling the methods of a Controller that has already been developed, but in doing so your are creating TIGHT coupling between both controllers! If something changes in the borrowed controller, it will have an effect on the borrowing controller. Not good, Dr. Jones.