6

My problem is actually not the ajax loading itself, more the capability to load it without javascript. I mean, I cope easily when I code my whole project just based on ajax-availability OR just without the use of ajax.

//EDIT: Although Arend already had a more or less valid answer, at the same time 'there is no direct answer to this question'. However, I'd like to see some other approaches of developers for scenarios like mine though! Even just a few links can help!

Basically I just get frustrated, coding everything twice on the same page to make sure that both users without and with Javascript enabled have the same experience. It's annoying and I was always wondering how others solve this problem.

When I update for example two divs with dependency on the same variables, it gets messy. Here's an example:

non-js-version

require 'classobject.class.php';
$another_var = 'something';
$class = new classobject($_POST['variable']); // just an example to show that this is dynamic - I'm aware of injection!
$function = $class->returnsth(); // returns 1

if(isset($_POST)) {
    echo '<div id="one">Module 1 says:'; $require 'module_one.php'; echo '</div>';
    echo '<br /><br />';
    echo '<div id="two">Module 2 says:'; $require 'module_two.php'; echo '</div>';
}

Now in module_two.php and module_two.php I have code that executes differently depending on the return variable of $function. Like:

if($function >= 1 && another_var != 'something') {
   // do stuff
}
else { 
   // do other stuff 
}

Now as this works easily with a reload, when I want to load the two modules on keyUp/enter/submit or whatever, I have basically a few problems:

  • I have to send the $_POST variables manually to the modules to use them
  • I have to re-execute the class & it's methods and make a link (require_once) to them in each of the module-files.
  • As $another_var is not existent in the modules, I'd have to send this variable to each modules, too (with post for example) and then before it can be used, I'd have to 'change' it like $another_var = $_POST['another_var'];

I find this mildly annoying and I wonder how you guys do that. I hope my way of coding is not too silly, but I can't think of another way. It's probably hard to relate to my very basic example, but to bring a whole project with the code would be too much. To sum it up, I'm looking for a better way to code and clean this mess up - there must be a way! I thought about sessions, but for compatability I don't want to rely on them either (if someone doesn't allow cookies).

In case you can't relate to what I'm trying to accomplish with that way of having my code assembled, I'll explain a scenario I'm facing quite a lot (not important if you already understand my misery):

  1. Basically I have my index.php page where everything gets executed, with the html body and css styling and so on. This page expects some variables, that get set from the page that requires the index (like $another_var in my example).
  2. Now other variables can get set too (from a form for example). Depending on that different classes and methods load new variables (arrays) that get used in while-loops in my modules to echo everything out.

Hope that's not too abstract. Think of a booking system where some variables are set from the page you are coming from (the event you want to book) and then a few more things get set by the user (a timespan, some preferences,...). In the end it's supposed to show results from the database all the way to the end-result - you can say the user narrows the results from step to step.

Anonymous
  • 3,679
  • 6
  • 29
  • 40
  • 3
    I find [progressive enhancement](http://en.wikipedia.org/wiki/Progressive_enhancement) and the [strategy pattern](http://en.wikipedia.org/wiki/Strategy_pattern) quite helpful for handling ajax and non-ajax. – Herbert Dec 01 '11 at 11:29
  • @Herbert I had a thorough read on your linked articles and a few more I found with Google as well. Still struggling a bit with a concrete idea how to use it with the handling of ajax and non-ajax sites. Do you have some code to make it a bit clearer to me how you would do this ? – Anonymous Dec 02 '11 at 13:29

2 Answers2

11

There is no direct answer to your question, but there is some food for thought.

Seperation of concerns You can think about if you can perhaps seperate your buisness logic and layout logic. Often the use of a template engine can help greatly with that. I've had positive experiences with for example Twig or Smarty (was some time ago, not sure how they measure up right now). It requires you to write your code in a (less linear) way, but more logical.

A typical example of an OOP like seperation of concerns might be something like this:

$this->setParam('Myparam','myvalue');

if ($this->isAjax())
{
    $this->setTemplate('ajax.php');        
    $this->setLayout(false);
} else {
    $this->setTemplate('normal.php');
    $this->setLayout('Mylayout');
}

return $this->render();

It is an imaginative situation, which can be found in many MVC like applications and frameworks. The main idea is that you should have the possibility to seperate your layout from your data. I would suggest looking at some of the modern frameworks for inspiration (like symfony, codeigniter, zend framework).

Glossary / Often applied concepts in a decoupled PHP application Here is a quick list of concepts that can be used.

Example mvc in php: http://www.phpro.org/tutorials/Model-View-Controller-MVC.html

Note: I don't really like the implementation. I much more prefer the existing frameworks. I do like the explanation in total of this tutorial. E.g. for me this link is for learning, not for implementing.

Silex For a simple decoupled php micro-framework I would really recommend silex, by the makes of symfony2. It's easy to implement, and to learn, but contains mainy of the concepts described here; and uses all the php 5.3+ goodies such as namespacing and closures.

see: http://silex.sensiolabs.org/

Frontcontroller Pattern Only have one, and one only point of entry for your code. I usually only have one, and one only point in your application. Usually a frontcontroller 'dispatches' the request to the rest of the application

http://en.wikipedia.org/wiki/Front_Controller_pattern

Routing

A routing system is often used in combination with the frontcontroller pattern. It basically describes which URL is connected to which module / controller. This allows you to change the way people access your app without changing the urls.

See: https://stackoverflow.com/questions/115629/simplest-php-routing-framework

Controller

A controller is the place where buisness logic is applied. Getting the data from the database, checking privileges, setting the template, setting the layout, etc. (although this is also moved outside the controller if it becomes too big of a seperate concern).

Model The model basically is the layer in which use manage your database. This can be a simple class where you move all your mysql_* functions, or it can be a full-featured ORM. The main philosphy is that all the logic related to fetching and placing information in the database is seperated.

One step up: ORM An often used method in applications are Object Relational Models, these 'map' SQL records to PHP objects. Doctrine and Propel are two of these well worked out libraries. I heavily rely on these systems in my development. In this sense, the doctrine or propel part will represent the model layer.

View: The view usually consists of a templating engine. Some use plain PHP as a template, others, such as symfony create a seperate scope in which variables are placed. There are many discussions and opinions about what is best, one is right here on stackoverflow:

Ones I like: - Twig: http://twig.sensiolabs.org/ - sfTemplate: http://components.symfony-project.org/templating/ - Smarty: http://components.symfony-project.org/templating/

Decoupling mechanisms:

  • Event based systems Using events in your can help to seperate the code. For example if you want to send an email after a record has been saved, events are a good solution to do that; in general the model should not have to know about email. Thus events are a way to connect them: you can let your -email-send-class listen to certain records in order for them to send the right email. (Perhaps you'd rather want your e-mails send from your controller, this is probably a matter of taste).

  • Dependency injection When using OOP code in PHP many relied on having singleton classes running around (configuration, etc). From an OOP point of view, this can be considered bad, because it's hard to test it, and it's not considered very elegant to have dependencies running around like that. Dependency Injection is a pattern that came form Java and is now used in the newer frameworks to get around this. It might be a bit difficult to wrap your head around, but you will see it coming back in several new frameworks.

Dependency injection in php: Dependency Injection in PHP 5.3

Frameworks:

A lot of these methods are difficult, or a lot of work to implement yourself. Many will reside to a framework for this. You may or may not need a framework. You may, or may not want to you a framework, it's your choice. But it's still useful to learn how the frameworks do it, and not try to reinvent the wheel yourself.

The no-framework php frameworks: https://stackoverflow.com/questions/694929/whats-your-no-framework-php-framework

Good habits: https://stackoverflow.com/questions/694246/how-is-php-done-the-right-way

Frameworks worth looking at (imho): CodeIgniter, Kahona, CakePHP, Symfony (1.4/2.0), Silex, Zend Franework, Yii. There are many many more, each with their dedicated fans and haters.

Community
  • 1
  • 1
Arend
  • 3,741
  • 2
  • 27
  • 37
  • It sounds like this is what I'm looking for - theoretically. Because I code and design all by myself, I never really considered using a template engine, but maybe this is the time I should look into it. Will have a look at it, thanks! But in your 'imaginary' example, wouldn't that mean for me that I basically write the same, just seperate it a bit more/better ? – Anonymous Nov 26 '11 at 21:32
  • 2
    It's more an example how a lot of MVC (Model, Controller, View) like applications work; but it requires a bit more of abstract coding. (Not always very exciting stuff to do yourself). I'll ad some links for you to the post as a bit of background information. – Arend Nov 26 '11 at 21:36
  • Sorry for the delay, I'll look it up tonight. – Arend Nov 28 '11 at 19:11
  • 2
    I just want to re-enforce what Arend has said. This question really needs ~2,000 lines of source code to answer. The basic concept though, is you should be able to setup an environment where your code for processing the data is used for both ajax and non-ajax requests, and only the final output (HTML vs JSON) changes. Precisely how it's done is really a matter of personal taste. Study Zend/etc a bit for inspiration. Don't restrict yourself to PHP! Check out Ruby on Rails or the iPhone's UIKit, both are MVC frameworks better than any PHP one I know of, full of good techniques to borrow. – Abhi Beckert Dec 03 '11 at 07:48
  • 2
    A good start is to make sure *every* table has a single "model" class dedicated to queries on it. And use templates for your HTML (you can use PHP for template files, but they should be exclusively for generating HTML and not contain anything more complex than basic if statements), and then you have a "controller" class who's job is to tie all of it together. They don't do any database queries, or any print any HTML. In very complex code you may have multiple classes per table, and tens or even hundreds of controller classes, and template files might push some of their work to classes as well. – Abhi Beckert Dec 03 '11 at 08:00
  • Thanks a lot for your response @AbhiBeckert, after some more reading, I think I got some kind of an approach (only in my thoughts yet). I'm still a bit confused though about the controller. What would be a good approach to connect the ajax requests with the 'normal' ones ? Or would you rather write a separate controller for each ? – Anonymous Dec 04 '11 at 13:04
  • 3
    I think you should use the same controller, since anything important done with ajax often needs to be possible without ajax too. Therefore, it's going to have a lot of crossover. I would simply have a boolean in your controller "isAjaxRequest" you can query at any time to do a simple if statement for anything ajax specific. – Abhi Beckert Dec 05 '11 at 07:55
  • thank you all so much for everything!! I definitely made a step forward with this question! – Anonymous Dec 05 '11 at 21:31
0

I wrote something like this with PHP. I already had abstracted the rendering of every page such that I define a $content variable and then require('layout.php'). The $content variable is just a big HTML string.

I wrote a PHP function to determine if request was AJAX or not.

The non-AJAX responses render the layout with $content in the middle, b/t header and footer layout content.

AJAX requests basically get this: json_encode(Array("content"=>$content)). And I use jQuery to get the HTML out of the JSON response and modify the DOM. Using json_encode() will handle escaping the string for javascript.

In the end, I effectively have AJAXified every page w/o over-engineering a complex solution.

Any browser that supports AJAX can also open a link in a new tab/window to simulate the non-AJAX request. (Or bookmark/share a link, too.)

Teddy
  • 18,357
  • 2
  • 30
  • 42
  • Sorry, I don't really understand your approach here. How is that related to my problem where I have a pre-defined php-variable that is necessary for the execution of another script ? – Anonymous Dec 05 '11 at 16:10
  • It is a response to 'I just get frustrated, coding everything twice on the same page'. I am assuming that the top and bottom of the page don't change and the only thing that needs to be updated for AJAX requests is the stuff b/t the top and bottom. If the stuff b/t the top and bottom can be expressed as a string variable, it can be outputted as an AJAX response or stuck between HTML that makes top and bottom of page in a full page response. Thus, you won't have to code everything twice. – Teddy Dec 05 '11 at 18:48
  • Your assumption is right, but I think you misunderstood my question (no offence, it's probably not easy to grasp exactly what I want). Basically my statement with the 'coding twice' was referring to the fact that I have some arrays/vars etc set on the landing page and it's no problem without ajax, but when I load with ajax I have to pass them again/execute some methods and their params again.\ – Anonymous Dec 05 '11 at 20:37