I am designing an Email controller with actions like actionRegisterEmail and actionForgotPasswordEmail.
This would help me to view the emails in browser also while assigning dummy data if data is not set.
class EmailController extends Controller
{
public $layout='email';
public function actionForgotEmail(ResetPasswordEmail $forgotModel=null){
if($forgotModel == null){
$forgotModel = new ResetPasswordEmail;
$forgotModel->name = "John Doe" ;
$forgotModel->link = "a url" ;
}
return $this->render('reset_password',$forgotModel);
}
}
When I'll be sending this emails I will be instantiating the controllers and fetching their returned html which they return with $this->render.
The idea is good according to me but yii doesn't allow me to call action methods on instantiated controllers like
$emailController = Yii::app()->createController('email');
$vary = $emailController->actionForgotEmail($reset);
todb_and_mail($vary);
.
This way I can mail the rendered html and also test with dummy. But I have come across many posts which says do not instantiate controller use components.But I want to have a seperate view and pass data to it.Do we have any more simpler alternative ?
Just to help anyone with the same doubt.I instantiated a dummy controller and set its layout and called the render method then.
class MailHelper extends CComponent {
public static function getEmail($view_template,$data){
$controller = new CController('Email');
$controller->layout = "email" ;
return $controller->render($view_template, $data, true);
}
}
This way I can get the functionality of passing variables and data to view.We are using static html for visibility of the view files directly from the browser, this was actually simple I made it complicated to get the other things involved thanks davey for guiding me right.
Related
I'm trying to create my own little PHP-Framework just for fun and to learn.
But now I stuck with the View.
class Index extends Controller {
function __construct() {
parent::__construct();
$this->view->msg = 'This message is sended over the view.';
$this->view->content = 'This is the INDEX-Content.';
$this->view->render('index/index');
}
public function something() {
// do something
// and render it
$this->view->content = 'This is the content from something.'
}
So what I can do is to misuse the __destruct and render here my output. But I guess that is against the purpose of this method.
When I compare my intention with e.g. Zend Framework or Laravel they use e.g. an after() method to render a view.
But I do not understand which method can do this. The constructor is the first, the destructor the last and everything between it has to be called to work.
Are there any "magic" methods for this?
You should handle your HTTP I/O
This is how you can output
This is how a request is executed
This is how the action is triggerd
Sniff through the repo as much as you can, Kohana is a simple yet powerfull framework. (you can learn a thing or two)
You can do something like this in your main Controller class :
public function __call($method,$arguments) {
if(method_exists($this, $method)) {
call_user_func_array(array($this,$method),$arguments); //this is where the function is called
$this->render();
}
}
You can eliminate in hear constructors, destruct and other functions that you do not want to automatically render.
You can also have a variable in your main Controller class, autoRender set default to false and just set it to true when you want to produce a predefined output.
Also in the _call function, you can use the $method variable to have a predefined name for your view. Like for example lets say you would have a folder in your framework called Views and in there you would have a file called something.view_extension.
You can send to render like this : $this->render($method.'.view_extension');
Just a bulk idea you can work around. :)
Good Morning everyone. Recently i've read an article about mvc pattern saying that most of the php frameworks out there implemented the mvc pattern wrong.
php master mvc pattern part 1
php master mvc pattern part 2
Well after reading this and looking over that implementation a question appeared.
How on earth would call in the view the method called in model? What i'm trying to say is this.
This is a piece of code from the article.
<?php
$model = $_GET['model'];
$view = $_GET['view'];
$controller = $_GET['controller'];
$action = $_GET['action'];
if (!(empty($model) || empty($view) || empty($controller) || empty($action))) {
$m = new $model();
$c = new $controller($m, $action);
$v = new $view($m);
echo $v->output();
}
let's say we've written a small implementation of this design pattern after reading the article and we have the following code:
<?php
class Index extends Controller
{
public function __construct(IndexModel $model, $action)
{
$this->model = $model;
}
public function someAction($id)
{
$this->model->getData($id);
}
}
class Index extends View
{
public function __construct(IndexModel $model, $action)
{
$this->model = $model;
}
public function someAction()
{
$this->model->getData();
}
}
class Index extends Model
{
public function __construct()
{
//Some Code Here
}
public function someAction()
{
// Inserting Data into database.
}
}
As you can see we are calling the same method both in controller and in view to get the data from the database. But if i know correctly the view should take care of the controller's job so the $id wouldn't be right to parse it again in the view or something like that. Then how this can be solved?
There's no 1:1 correlation between controllers and parts of the model (note: not "models" but parts of _the model_). Just because you have an "index controller" doesn't mean you need an "index model" and "index view".
The M, V and C are not constructed together. The controller is constructed, and then it decides which model method to load/construct/invoke and which view should respond to the request.
There's discussion about whether the controller should invoke the view, or whether the model should "update" the view. Since web requests are ephemeral and there's no "constant" view, the latter makes little sense in PHP; it's more appropriate for the original SmallTalk or Obj-C or similar environments.
The first code snippet has terrible use of empty (see here) and, again, should not construct all parts together.
MVC should be approached like this:
The model is the app. It's not just a "data handler" or "data store", it is the core app. Everything the app does, business logic wise, is "the model". This includes sending email notifications, database maintenance work and such auxiliary things, they're all in the model.
The view is responsible for producing output of various forms. The view should be able to interact with the model to get the data it needs to do its job. Data should not be "pushed into" the view, the view should be able to "pull" the data it needs; otherwise something external to the view needs to know what data the view needs, which means the view logic is not self contained in the view anymore.
The controller is just the little bit of glue that's left to invoke the correct model method and view in response to the incoming request.
I typically structure these parts like this:
The model consists of various parts, including data storage handlers, "primitives" (classes that model individual business objects) and "services". The "services" contain all the "actions" your app can do and form the model API. Whenever you want to "do" something in the app like "register a user" or "fetch all records for date range X through Y", there's one specialized method for it in the service API. Just looking at this service API you should be able to enumerate all the things your app "does".
There's one object which is either a "dispatcher" or a "service locator" or simply a dependency injection container that simplifies instantiation of these service classes and allows someone to call them. The controller gets one of these and so does the view.
There's a router which does some "rough routing" based on the URL, invoking a controller method. The controller further looks at the details of the request and decides to call a model method and/or to respond with a view.
The view may decide the best way to present some data based on the specifics of the request, e.g. whether to respond with an HTML page or a JSON data blob. Yay for RESTful services.
In rough pseudo code:
$r = new Router;
$r->route($_GET, $_POST, $_SERVER); // or something like that
This dispatches to something like:
class FooController {
public function __construct(ServiceLocator $services) { ... }
public function bar(Request $request) {
$request->assertIsPost();
$this->services->locate('Baz')->froogleTheWibbles($request->getPostParams());
(new BarView($this->services))->displayWibbles($request);
}
}
class BarView {
public function __construct(ServiceLocator $services) { ... }
public function displayWibbles(Request $request) {
switch ($request->accepts()) {
case 'html' :
$this->loadTemplate(...);
...
case 'json' :
echo json_encode($this->services->locate('Baz')->getWibbles());
}
}
}
And the model does whatever it needs to do...
class Baz {
public function froogleTheWibbles(array $data) {
foreach ($data as $wibbleData) {
$wibble = new Wibble($wibbleData);
$this->wibbleStore->save($wibble);
}
...
}
}
There is no "one answer" for MVC, the important part is that the model contains everything your app "does" independent of input and output, the view can produce the right output as requested as independently as possible and the controller is just the little bit of glue that handles input conditions. There are various ways in which this can be realized. The important design principle should be the realization that the view and controller are interchangeable to fit different conditions (web page, JSON API, XML API, SOAP API, CLI invocation, ZeroMQ node etc.), but "the model" is not.
I realize this topic has been asked and addressed repeatedly, and although I've read through countless similar questions and read through countless articles, I'm still failing to grasp a few key concerns... I'm attempting to build my own MVC framework for learning purposes and to better familiarize myself with OOP. This is for personal private use, not to imply that as an excuse for being lazy, but rather I'm not so concerned with having all the bells and whistles of more robust frameworks.
My directory structure is as follows:
public
- index.php
private
- framework
- controllers
- models
- views
- FrontController.php
- ModelFactory.php
- Router.php
- View.php
- bootstrap.php
I have an .htaccess file with directs all requests to index.php, this file contains basic configuration settings such as timezone and global constants, and it then loads the bootstrap.php file. The bootstrap contains my autoloader for classes, starts the session, defines global functions to use throughout my project, and then calls the router. The router picks apart the request from the URL, validates it using a ReflectionClass, and executes the request in the form of example.com/controller/method/params.
All of my controllers extend the FrontController.php:
<?php
namespace framework;
class FrontController
{
public $model;
public $view;
public $data = [];
function __construct()
{
$this->model = new ModelFactory();
$this->view = new View();
}
// validate user input
public function validate() {}
// determines whether or not a form is being submitted
public function formSubmit() {}
// check $_SESSION for preserved input errors
public function formError() {}
}
This front controller loads the ModelFactory:
<?php
namespace framework;
class ModelFactory
{
private $db = null;
private $host = 'localhost';
private $username = 'dev';
private $password = '********';
private $database = 'test';
// connect to database
public function connect() {}
// instantiate a model with an optional database connection
public function build($model, $database = false) {}
}
And base View:
<?php
namespace framework;
class View
{
public function load($view, array $data = [])
{
// calls sanitize method for output
// loads header, view, and footer
}
// sanitize output
public function sanitize($output) {}
// outputs a success message or list of errors
// returns an array of failed input fields
public function formStatus() {}
}
Finally, here is an example controller to demonstrate how a request is currently processed:
<?php
namespace framework\controllers;
use framework\FrontController,
framework\Router;
class IndexController extends FrontController implements InterfaceController
{
public function contact()
{
// process form if submitted
if ($this->formSubmit()) {
// validate input
$name = isset($_POST['name']) && $this->validate($_POST['name'], 'raw') ? $_POST['name'] : null;
$email = isset($_POST['email']) && $this->validate($_POST['email'], 'email') ? $_POST['email'] : null;
$comments = isset($_POST['comments']) && $this->validate($_POST['comments'], 'raw') ? $_POST['comments'] : null;
// proceed if required fields were validated
if (isset($name, $email, $comments)) {
// send message
$mail = $this->model->build('mail');
$to = WEBMASTER;
$from = $email;
$subject = $_SERVER['SERVER_NAME'] . ' - Contact Form';
$body = $comments . '<br /><br />' . "\r\n\r\n";
$body .= '-' . $name;
if ($mail->send($to, $from, $subject, $body)) {
// status update
$_SESSION['success'] = 'Your message was sent successfully.';
}
} else {
// preserve input
$_SESSION['preserve'] = $_POST;
// highlight errors
if (!isset($name)) {
$_SESSION['failed']['name'] = 'Please enter your name.';
}
if (!isset($email)) {
$_SESSION['failed']['email'] = 'Please enter a valid e-mail address.';
}
if (!isset($comments)) {
$_SESSION['failed']['comments'] = 'Please enter your comments.';
}
}
Router::redirect('contact');
}
// check for preserved input
$this->data = $this->formError();
$this->view->load('contact', $this->data);
}
}
From what I'm able to understand, my logic is off for the following reasons:
Validation should be done in the Model, not the Controller. However, a Model should not have access to $_POST variables, so I am not entirely sure whether or not I'm doing this part correctly? I feel like this is what they call a "fat controller" which is bad, but I'm not sure what needs to change...
The controller should not send data to the View; instead, the View should have access to the Model to request its own data. So would moving the $data property out of the FrontController and into the ModelFactory, and then calling the View from the Controller without passing along data resolve this issue? Technically it would then adhere to the MVC flowchart, but the proposed solution seems like such an insignificant or even trivial detail, assuming it's that simple, which it probably isn't..
The part that has me questioning my whole implementation is that I have a User object that is instantiated with a users corresponding roles and permissions, and I've been trying to figure out how or more specifically where to create an isAllowed() method that can be called from both the Controller and View. Would it make sense then to put this method in the Model, since both the Controller and View should have access to the Model?
Overall, am I on the right track here or what glaring problems do I need to address in order to get on the right track? I'm really hoping for a personal response specific to my examples rather than a "go read this".. I appreciate any honest feedback and help.
The $_POST superglobals should be abstracted by a request instance, as explained in this post.
Input validation is not the responsibility of the controllers. Instead it should be handles by domain objects within model layer.
Model factory is no a model.
Defining class parameter visibility as public breaks the object's encapsulation.
HTTP location header (redirect) is a form of response. Thus, it should be handled by view instance.
In its current form, your controllers are directly manipulating superglobals. This causes tight coupling to the globals state.
Authorization checks should be performed outside controller. Not inside of it.
Your "model factory" should instead be a service factory, that is injected in both controller and view. It would ensure that each service is instantiated only once and thus let your controllers work with same model layer's state.
First, I think it's great you are trying to create you own framework. Many say that everyone should do this, if only for learning purposes.
Second, I would suggest you read this Wikipedia article on frameworks. Many people don't realize there are different patterns for routing (url dispatch, traversal), and views (push, pull).
Personally, I don't see a need to abstract out the super globals since they are already abstractions (by php) from the raw input (php://input) and can be modified. Just my opinion.
You are right that validation should be done by the Model. You don't validate forms, you validate data. As for the View accessing the data, that depends on the pattern you choose. You can push the data to the View, or the View can pull the data.
If you are curious, my attempt at a MVC basic framework is on github. Its 4 files, less 2K line of code (DB layer is 1K lines). It implements traversal (component) routing and pulls data, there were already plenty of frameworks that implement the alternate patterns.
Validation should be done in the Model, not the Controller. However, a
Model should not have access to $_POST variables, so I am not entirely
sure whether or not I'm doing this part correctly? I feel like this is
what they call a "fat controller" which is bad, but I'm not sure what
needs to change...
That is right, Model should know nothing about the request, so, you need to pass $_POST to the models, but it will not know that are request parameters.
One thing: validation that has nothing to do with business logic should stay in controller. Let's say, you create a CSRF token for your forms for security reasons, this valitadion should be inside the controller, because it handles requests.
The controller should not send data to the View; instead, the View should have access to the Model to request its own data. So would moving the $data property out of the FrontController and into the ModelFactory, and then calling the View from the Controller without passing along data resolve this issue? Technically it would then adhere to the MVC flowchart, but the proposed solution seems like such an insignificant or even trivial detail, assuming it's that simple, which it probably isn't..
That's not necessarily true. This approach is called Active Model, and normally you use the Observer pattern, with models being observed by the views. If some model changes, it notifies the view that will update itself. This approach is more suitable for desktop applications, not web-based ones. In web applications, the most common is to have controllers as intermediaries between model and view (Passive Model). There's no right approach, you should choose the one you like the most.
The part that has me questioning my whole implementation is that I have a User object that is instantiated with a users corresponding roles and permissions, and I've been trying to figure out how or more specifically where to create an isAllowed() method that can be called from both the Controller and View. Would it make sense then to put this method in the Model, since both the Controller and View should have access to the Model?
Well, this one there's no way, I'll have to tell you to read about ACL.
I was too sleepy when I asked the question, so sorry for that, anyway to make things clear I prepared the question for 2 hours.
I'm trying to organize my code and decided to organize it mvc'ish(mvc-like), I don't know if I can follow all the principles, but I wanted to be at least close to that.
My application has a front-controller (dunno if my definition is right), so that all the http-request of my application will be passing through a single point, in my case the index.php in the root directory of my application.
Having said that I have set it up like that, you can imagine that I used .htaccess to direct all request to index.php.
I exploded the url and created an array out of it, $url[] like so. So whenever I access my app like this http://localhost/app/pagename it'll be accessing a controller (pagename_controller)
I did it like this :
$file = $controller_path . $page . '_controller.php';
if (file_exists($file)) {
require $file;
$class_name = ucfirst($page) . '_controller';
$target = new $class_name();
}
also I wrap it up in a Container, the 'decorator pattern', for future use, validations maybe.
like this :
$controller = new Wrap($target);
$controller->index();
I don't know if the use of $controller variable name is appropriate so please forgive me when it is all wrong.
I kinda think that I can setup my application like this :
user sends a request, how? by using the application means that he/she sends out a http-request, that will load the initial state of the application
As you can see in the diagram of my desired application structure, I was able to do only the first part which is to direct the request to a single entry (index.php)
Now the problems are the initialization of other parts of the application.
As of this moment, I have 3 files that I want to setup, but I am confused on how.
index_controller, index_view, Template
class Index_controller {
private $model;
private $view;
public function __construct(){
// optional model -> $this->model = 'index'
$this->view = 'index' //
}
public function index(){
$this->load->view($this->view)
}
}
class Index_view {
private $model;
private $template;
public function __construct(Model $model = null){
$this->template = new Template('default');
}
public function view() {
$this->template->assign('css', 'default_css'); // don't know if this is efficient
// or $this->template->assign('header', 'default_header');
// or $this->template->assign('sidebar', 'default_sidebar');
// or $this->template->assign('footer', 'default_footer');
// or any other things I want to use in the template
}
}
class Template {
public $data = array();
private $tmpl;
public function __construct($template) {
$this->tmpl = $template . '_tmpl.php';
}
public function assign($name, $value){
$this->data[$name] = $value;
}
// public function output
// function that will explode the data array and render it out as a webpage
// I'll create templates and
}
With that at hand, I want to know now how do I link those things together. At the moment I have a system folder that can contain classes, and I setup a autoloader for that folder.
I am thinking of creating a Controller class and View class that acts as the ActionFactory and ViewFactory as illustrated in the diagram, although I know that these are not their responsibilities.
I am thinking of this :
class Controller {
protected $load;
public function __construct() {
$this->load = new View();
}
}
class View {
public function __construct() {
// some things i don't know
}
public function view() {
// some things i don't know
}
}
What are your suggestions and comments in my setup. How can I initiate the triad?
Well, let's not get stuck on your implementation details too much. You can go read about securing your framework at some other time. Let's deal with your question...
I actually created a framework that works along the lines you are trying to implement. I think what you are missing is a RoutingHandler class. Routing is the physical manipulation of the URL, which tells your application which Controller to load, and which Action to run.
In my world I also have Modules, so the basic routing scheme is
Module -> Controller -> Action
These three items map to my URI scheme in that fashion. Variables can be appended also like so...
http://www.domain.com/module/controller/action/var1/val1/var2/val2
So, what happens after the URI is parsed, and control is passed over to the appropriate controller and action? Let's make some code up to demonstrate a simple example...
<?php
class indexController extends Controller {
protected function Initialize() {
$this->objHomeModel = new HomeModel;
$this->objHeader = new Header();
$this->objFooter = new Footer();
$this->objHeader
->SetPageId('home');
}
public function indexAction() {
$this->objHeader->SetPageTitle('This is my page title.');
}
}
?>
In the Initialize method, I'm setting some controller-wide stuff, and grabbing an instance of my Model to use later. The real meat is in the indexAction method. This is where you would set up stuff to use in your View. For example...
public function randomAction() {
$this->_CONTROL->Append($intSomeVar, 42);
}
_CONTROL is an array of values that I manipulate and pass onto the View. The Controller class knows how to find the right template for the View because it is named after the Action (and in a sibling directory).
The Controller parent class takes the name of the action method and parses it like so...
indexAction -> index.tpl.php
You can also do some other fun stuff here, for example...
Application::SetNoRender();
...would tell the Controller not to render inside a template, but just complete the method. This is useful for those situations where you don't actually want to output anything.
Lastly, all of the controllers, models, and views live inside their own directory like so...
my_module
controllers
indexController.class.php
someotherController.class.php
:
:
models
HomeModel.class.php
:
:
templates
index.tpl.php
someother.tpl.php
:
:
I could go on, but I'm writing this from memory, and there are some wrinkles here and there, but hopefully this gives you food for thought.
I am relatively new to Joomla and the way they implement an MVC arcitecture. It is slighty different to how I am used to it (Code Igniter, etc) and I am having a few issues simply passing data to the view.
I have created a function in the controller called 'getInitClubs' which sould be run automatically when the page runs, therefore I have made a call to this function from the 'view.html' file.
Here is my code:
Controller function:
public function getInitClubs() {
$model =& $this->getModel('directory');
$init_clubs = $model->clubResults($conds = array());
return $init_clubs;
}
Model Function:
public function clubResults($conds) {
$query = "SELECT * FROM vyj20_contact_details";
if(isset($conds['city'])) {
$query .= " WHERE state = '" . mysql_escape_string($conds['city']) . "'";
}
if(isset($conds['suburb'])) {
$query .= " AND suburb = '" . mysql_escape_string($conds['suburb']) . "'";
}
$this->_db->setQuery($query);
$results = $this->_db->loadObjectList();
return $results;
}
Now i know the model and controller code works, this is not the issue, the issue is actually pulling the results from the controller function 'getInitClubs' and showing them through the view.
How do I call the controller function from the view (like I would on Code Igniter MVC) in order to collect results for display? I have tried and tried but just can't seem to figure it out!
Thanks
The JView instances has getModel() method. You get the model instance you access a static registry, which is shared between all components. In the JController instance you should change the state of that model and in the JView instance you should pulling out the data.
Views in MVC design pattern are supposed to acquire information from model layer and render it using templates or, in some cases, just send a simple HTTP header. In this aspect Joomla has a surprisingly good take on MVC pattern.
P.S. since PHP 5.0 was released (some time around 2005th), you do not need to use references when assigning objects. It is actually harmful, because it messes with refcount.
You controller function should be like.
$model =& $this->getModel('directory');
$init_clubs = $model->clubResults($conds = array());
$view = $this->getView('view_name', 'html'); // get the view
$view->assignRef('data_list', $init_clubs); // set the data to the view
$view->display(); // show the view
Read more
Developing a Model-View-Controller Component
Model-View-Controller
Developing a Model-View-Controller Component/
Model View Controller