Some background: I came from a .Net environment where we had to use MVVM in all of our projects to separate the view from the viewmodel. Now that I'm working on my own personal PHP project I decided to use the same design and separate the view and viewmodel.
So on the view I create a viewmodel object and call background functions when necessary and in the view the code is only to provide the display.
Example:
view.php
<?php
include('viewmodel.php');
$vm = new viewmodel.php();
if(some condition)
{
$vm->doSomething();
}
?>
<html>
<body>
//some form code
</body>
</html>
viewmodel.php
<?php
//includes
class viewmodel
{
function viewmodel()
{
}
function doSomething()
{
}
}
?>
Now that I've learned jQuery I want to use it to make my pages more dynamic, have less traffic back and forth to the server and less need for page refreshing.
I've seen calls like this that allow jQuery to call a php page with some some post data:
$.ajax({ url: '/my/site',
data: {action: 'test'},
type: 'post',
success: function(output) {
alert(output);
}
});
However this is no longer Object Oriented Design and I would have to remove all the class definitions from my viewmodels for this to work.
Is there any way for jQuery to make those calls to the viewmodel or does using jQuery mean you have to return to a procedural style of programming?
However this is no longer Object Oriented Design and I would have to remove all the class definitions from my viewmodels for this to work.
What makes you think that? There's nothing inherently object-oriented or non-object-oriented about making AJAX requests to the server. Nor do these client-originated requests have any bearing on the architecture of the server-side code.
In your views you can have any JavaScript code you'd like. It won't make a difference to the server-side code rendering the view, as the JavaScript is just text as far as it's concerned and no different than the HTML.
As for the server-side handler, what you'll probably want to do is create entirely new views and viewmodels for the "page" ("resource" is a more accurate word) that's being called by the jQuery code.
So, for example, you might get a request from the browser for something like /my/site which would, using the architecture you have in place, populate a viewmodel to bind to a view and return that view to the client. That view would contain some JavaScript code, some of which calls another resource. Let's say that other resource is something like /api/products which returns a list of "products" available for the user.
Note that I put the resource under a different path, api instead of my. This was a pretty arbitrary decision, and it's only used to illustrate that what you're returning in this case isn't a "page" so much as it is JSON data for an automated API. The actual name of the resource can be anything you like, of course.
This resource can still be a view and be bound to a viewmodel, but in this case the view is JSON data instead of HTML. As with anything, there are many ways you can do this. A quick Google search turned up another question which talks about the differences between a couple of methods for generating JSON data. Indeed, your "view" in this case might be entirely empty and all you're doing is serializing a viewmodel to JSON and returning that. (My PHP is pretty rusty, but the ASP.NET MVC equivalent would be to return an ActionResult of Json() instead of View().)
Keep in mind that, from the perspective of the server-side code, there is no difference between returning a view in HTML vs. returning one in JSON (or XML, or raw text, or anything else). A view is a view, each one independent from the others.
Related
Using MVC I have something like this:
class Controller
{
//returns View
function indexAction()
{
$data = $this->getData($this->id);
$view = new ViewModel();
$view->setVariable('data' => $data);
//used to render HTML template + data above later on
return $view;
}
//gets data from DB
//currently also does business-proprietary computation on data
function getData($id)
{
//repository/dao pattern
$data = $this->repository->getData($id);
//Business Logic "derivation"
foreach ($data as $datum)
{
//that does not go into "Controller
//that does not go into "Repository"
//but where does it go? - that's my question
$derivedData[] = (new Business())->doLogic($datum);
}
return $derivedData;
}
}
Recap
I used Controller to get my data out of DB using Repository pattern, then placed received data into view. But business-related computations are left stranded.
Question
Where do I place my business logic computations that act on the data gotten from repository? The derived data which is to return to Controller later, to be placed into View?
My personal choices of architecture are usually to:
Have small controllers as thin as I can, doing only session and general right checking
Services that are handling all business logic, one (one classe yes) per potential feature I need
Services are querying repositories, and eventually manipulate the data in and out, but usually no Controller, nor view will do a ->save() anywhere.
This means that those services are usually designed to be independent from the database and easier to be tested because they only take care of one and only one task.
In your example, the whole function getData will be a service that I would call GetCarDataById. This assuming that you manipulate Cars, I don't like to leave data wandering alone.
EDIT: to make it clear, this kind of approach is not MVC to some definition, most people interpret MVC as putting all code either in controller, either in repositories (model). To others view, MVC doesn't mean that you have other classes, what I call services, and actually most of my code lives here.
The MVC pattern is clear for me.
From wikipedia:
The model directly manages the data, logic and rules of the
application. A view can be any output representation of information,
such as a chart or a diagram. Multiple views of the same information
are possible, such as a bar chart for management and a tabular view
for accountants. The third part, the controller, accepts input and
converts it to commands for the model or view.
Answering your question. The modifications goes in the model domain.
In our setup, we have models+mappers for all db objects. Then there are controller actions which prepare model objects for respective actions based on business logic.
We have send entire model object to the view and if view (html) wants to show first name, it can call $obj->getFirstName() or if some other view (pdf) can even call $obj->getFullName(). Is this how it is supposed to be done?
What if country was left empty and the view ignorantly calls $obj->getCountry()->getISO3Code() will be fatal since getCountry() returned false instead of a expected country object.
One option is to bother the view with IF.. etc so it is made safe. but does it not defeat the purpose that views should be dump without logic? or maybe I over stressed it.
should we send the entire model object to the view (as now) or safely prepare and send a array of viewable fields? It kinda it makes the action to be aware how PDF view looks like and html view looks like, again maybe defeating controllers purpose.
I confess that I struggle with the same question. When the controller/action sets values in the view - $this->view->someKey = 'someValue' - then there is an implicit expectation that that the controller is aware of what the view requires. I guess the general idea is that this is ok; the view is responsible for how to render the data it is passed.
There is nothing wrong with using if statements inside your view-scripts. It is pretty common to see something like:
<?php if ($someCondition): ?>
<!-- some markup here -->
<?php endif; ?>
in a view-script. For example, take a look at the partials associated to a pagination control.
I have created view-model objects - kind of a read-only version of my model intended for use in a view - that permits me to do things in a view-script that are a bit cleaner. For example, you could have a view-model object with a method like hasCountry(), so that your view-script could do something like:
<?php if ($viewmodel->hasCountry()): ?>
<p>Country: <?= $model->getCountry()->getISO3Code() ?></p>
<?php endif; ?>
Kind of a trivial example, but for more complex logic about the entity I am trying to render, I find that a view-model like this provides a home for some of that rendering-specific logic that doesn't feel right in the controller and seems a bit complex for a view-script.
I'm working with a PHP MVC Framework. Works really well. I like the separation of the business layer (model) with the business logic (controller). But i just stumbled upon a problem. Here's the thing:
Suppose i navigate to the following url:
http://localhost/user/showall/
In this case the userController.php is called and within that file there is a method showallAction() which gets executed.
In the showallAction() method i simply do a request to a model which gets all the users for me. Something like this:
public function showallAction()
{
// create userModel object
$users = new userModel();
// get all users and assign the data to a variable which can be accessed in the view
$this->view->users = $users->getAllUsers();
// render views
$this->view->render();
}
So this method gets all the users, assigns the data returned from the userModel to a variable and i can easily work with the returned data in my view. Just a typical MVC thing.
Now here comes the problem.
I also need to create a native iphone variant. Ofcourse the looks will be totally different. So all i actually want to do is to request this url:
http://localhost/user/showall/
And that it just gives me the array (in json format) back. So i can use that for the mobile development.
But this obviously can't be done right now because the showallAction() method assumes that it is for web browser display. It doesn't echo JSON formatted, instead it simply assings the array of users to a variable.
So that means i have to create another method "showallMobileAction()" in order to get the data, but specifically for the mobile device. But this is not an elegant solution. I'm sure that are better ways...
Anyone any idea how can i solve this problem??
In your situation i would modify the routing mechanism.
It would be useful, if you could add extension at the end of URL, which represents the format you expect, like :
http://foo.bar/news/latest >> HTML document
http://foo.bar/news/latest.html >> HTML document
http://foo.bar/news/latest.rss >> you RSS feed
http://foo.bar/news/latest.json >> data in JSON format
It's a simple pattern to recognize. And you can later expand this to add .. dunno .. pdf output, or Atom feeds.
Additionally , two comments :
Model is not a type of objects. Instead it is a layer, containing objects responsible for business logic, and objects responsible for data storage/retrieval.
View should be a full blown object, to which you bind the domain objects (objects responsible for business logic).
You could pass parameters to your url:
/user/showall/json
and get the third URL segment with a custom function or a built-in one. For instance, with CodeIgniter: $this->uri->segment(3).
Some frameworks will pass the additional parameters to your method. Just try this with the URL I wrote above:
public function showallAction()
{
print_r(func_get_args());
}
I'm not familiar with PHP MVC but in general terms I'd use the "accepts" HTML header field to request the response in either "text/html" or "text/json", the controller would check for the accepts type and return the response accordingly.
I am in the process of learning the MVC pattern and building my own lightweight one in PHP
Below is a basic example of what I have right now.
I am a little confused on how I should handle AJAX requests/responses though.
In my example user controller below, If I went to www.domain.com/user/friends/page-14 in the browser, it would create a User object and call the friends method of that object
The friends method would then get the data needed for the content portion of my page.
My app would load a template file with a header/footer and insert the content from the object above into the middle of the page.
Now here is where I am confused, if a request is made using AJAX then it will call a page that will do the process over, including loading the template file. IF an AJAX call is made, I think it should somehow, just return the body/content portion for my page and not build the header/footer stuff.
So in my MVC where should I build/load this template file which will have the header/footer stuff? ANd where should I detect if an AJAX request is made so I can avoid loading the template?
I hope I am making sense, I really need help in figuring out how to do this in my MVC I am building. IUf you can help, please use some sample code
/**
* Extend this class with your Controllers
* Reference to the model wrapper / loader functions via $this->model
* Reference to the view functions via $this->view
*/
abstract class Core_Controller {
protected $view;
protected $model;
function __construct(DependencyContainer $dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
public function load($model){
//load model
//this part under construction and un-tested
$this->$model = new $model;
}
}
user controller
/**
* 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/page-14
function friends()
{
//GET data from a Model
$friendsData = $this->model->getFriends();
$this->view->load('userFriends', $friendsData);
}
}
For me, I developed a separate object that handles all template display methods. This is good because you can then ensure that all the resources you need to display your UI is contained in one object. It looks like you've isolated this in Core_View.
Then, when an AJAX call is made, simply detect that it is an AJAX call. This can be done by either making the AJAX call through an AJAX object, which then references other objects, or you can take an easy approach and simply set an extra POST or GET field which indicates an AJAX call.
Once you've detected if it's an AJAX call, define a constant in your MVC such as AJAX_REQUEST. Then, in your template/UI object, you can specify that if it's an AJAX call, only output your response text. If it isn't, proceed with including your template files.
For me, I send it through an AJAX object. That way I don't have to worry about making a single output work for both cases. When it's ready to send a response, I just do something to the manner of print( json_encode( ...[Response]... ) ).
well, it would all start with normal request which would load the initial page. there are many options as to handle this but let's say that you start with /users/friends page which would list all your friends. then each of the friends should have link to specific friend's profile -- now this is the moment where ajax could kick in and you could ajaxify links to your friend profiles - this means that instead of normal you would instead use let's say jQuery and setup click handler in a such way that
$("a").click(function(){$.post($(this).attr("href"), null, function(data){$("#content").html(data);}});
this would use "href", and upon click would make post request to your backend. at backend, if you see that it's post, then you would just return the content for that particular friend. alternatively, if you have get request, you return all - header - content - footer.
if you use technique above, make sure to properly handle the data you receive. e.g. if there are further actions that should be done via ajax, make sure to "ajaxify" the data you get back. e.g. after updating html of the content, again apply the $("a").click routine.
this is just trivial example, to kick you off, but there are many more sophisticated ways of doing that. if you have time, I suggest reading some of agiletoolkit.org, it has nice mvc + ajax support.
You will need to use a different view. Maybe something like:
funciton friends() {
$this->view = new Ajax_Request_View();
$friendsData = $this->model->getFriends();
$this->view->load($friendsData);
}
I am new to Zend FW. I am looking to write a simple feedparser in a controller named Feedparsercontroller's indexAction. but i want to display the parsed feed output as a widget on my index page. how can i drive the output/ variable data to my indexview?
The below is my parser.
class FeedparserController extends Zend_Controller_Action {
public function init() {
/* Initialize action controller here */
}
public function indexAction() {
$feedUrl = 'http://feeds.feedburner.com/ZendScreencastsVideoTutorialsAboutTheZendPhpFrameworkForDesktop';
$feed = Zend_Feed_Reader::import ( $feedUrl );
$this->view->gettingStarted = array ();
foreach ( $feed as $entry ) {
if (array_search ( 'Getting Started', $entry->getCategories ()->getValues () )) {
$this->view->gettingStarted [$entry->getLink ()] = $entry->getTitle ();
}
}
}
}
i want to implement the same with my login , register controllers as well.
Perhaps I'm not understanding your question fully.
But, it seems the best approach here would be to create a separate feed controller that is solely responsible for the business logic associated with feeds (retrieving, massaging, setting to view, etc).
Then, create a partial which contains javascript code to call the feed controller, which then outputs the widget you're desiring. This does a few things very well.
It centralizes feed-related logic
It allows you to place the feed widget wherever you want
It is a SOA approach which is generally a good thing
Hope this helps!
I think the best logic with widgets is ajax.
Use some js widgets libraries (maybe jQuery ui for example), then make these widgets be loaded by some ajax queries, returning HTML, this allow you as well simple widgets reloading behviours (without relaoding the whole page).
In the server Side you'll need to allow your controller/Action to be called via ajax requests and to send only html snippets (not a whole page with all the layout).
To do that check ContextSwitch and AjaxContext Action Helpers. You will tell your FeedparserController that the index action can be called with /format/html in an XMLHHTTPRequest, and that in this case the view helper will be index.
In the init part you will say the indexAction can be called in ajax mode, rendering html snippets ('html'):
$Ajaxcontext = $this->_helper->getHelper('AjaxContext');
$Ajaxcontext->addActionContext('index', 'html')
->initContext();
Now simply rename your view script feedparser/index.phtml to feedparser/index.ajax.phtml
In the indexAction, do your stuff and output what you want on your view script, do not think about layout composition problems, you're working alone with your own layout part and the composition is done on the js side.
In the javascript part, ensure you're calling via ajax ($.load or $.ajax with jQuery maybe) the url with format/html added as parameters (so http://example.com/feedparser/index/format/html)
Note that in my opinion you should use json responses and not html, maybe json with some html inside. But that's a matter on how you want to control your ajax communication (and handle errors, redirection and such, and it's another subject).
What about a view helper ?
You can read about it View Helpers in Zend Framework