I'm going to write a booking website using php and ajax and I really can't figure how to mix these two tools with a strict object oriented design.
I was used to make a call using ajax to a php web page that returns the right set of values (string, xml, json) in a procedural way.
With object oriented programming how is it supposed to work?
The simplest solution that i can think is to call through ajax a php page that should only instantiate a new object of the right class and then make an echo on the result of a simple call with the data received but this doesn't look very oo...
For example to implement the register function I should make an ajax call to a register.php web page that, in turn, will instantiate a new Registration object r and then simply calls r.register() with the right data.
Is there a better solution to this problem?
I want specify that I can't use any php framework because it's a didactic project and I have this rule that I should respect.
Another specification: I've read a lot of tutorials that describe how to write your own mvc framework but doing this seems to be an overkill for my problem.
Thank you for your help, every idea will be appreciated.
As you already said you don't really need a PHP framework and don't need to build your own MVC implementation
(especially if you are e.g. working with JSON or XML).
Basically you are pretty free on how to do your OO model, so your idea is not necessarily wrong.
Some OO anti patterns I have seen people using in PHP:
Use global variables in classes
Create classes without member
variables resulting in method calls
being the same as in a produral style
Directly accessing $_GET, $_POST etc.
in a class
Echoing html output (imho this should
be done in view templates)
An example for what you might want to do for the registering process processing some $_POST variables
and returning a JSON success message:
<?php
class Registration
{
private $_data;
public function __construct($registrationdata)
{
$this->_data = $registrationdata;
}
public function validate()
{
// ...
}
public function register()
{
// ...
if($this->validate())
return array("registered" => true, "username" => $this->_data["username"],
"message" => "Thank you for registering");
else
return array("registered" => false, "username" => $this->_data["username"],
"message" => "Duplicate username");
}
}
$reg = new Registration($_POST);
echo json_encode($reg->register());
?>
There is no reason to create any classes if all you are doing is calling a couple of unrelated stateless php functions.
Related
The more I read about dependency injection the more I get confused. I know what it is for, that is not the problem. Trying to do some design on paper this is what I came up with and somehow it seems to me I am overlooking something.
First I imagined building an actual server that would accept incoming requests and returns responses to the user.
class Server {
private $responseBuilder;
public function __construct($responseBuilder) {
$this->responseBuilder = $responseBuilder;
}
public function run() {
// create socket, receive request
$response = $this->responsebuilder->build($request);
// send response
}
}
class Response {
private $method;
private $message;
private $url;
// getters & setters
}
class ServerBuilder {
public build() {
// construction logic
return new Server(new ResponseBuilder());
}
}
Since Apache is used to handle server requests we could replace the server with something that just send the response.
$bldr = new ResponseBuilder();
$response = $bldr->build();
// send response some way
Note that ResponseBuilder has direct access to the request ($_SERVER['..'])
and so it has everything it needs to choose the right response.
PHP however allows us to build and send responses inline. So we could have a Controller object for each page or something else that send the response and have a builder for that.
$bldr = new ControllerBuilder();
$controller = $bldr->build();
$controller->run();
class ExampleController implements Controller {
public function run() {
header("HTTP/1.1 404 Not Found");
echo 'sorry, page not found';
}
}
This all makes sense to me. But let's look at the server example again.
It calls $responseBuilder->build() and gets a response back. But this would mean that the builder (or other builders if we split it) is also responsible for anything else that might occur like authenticating a user, writing to the database,... and I can't get my head around the fact that writing to a database would be part of the object graph construction.
It would be like: Send me your request. Oh you want the homepage? I will build you your response and while I'm at it I will also do some things that have nothing to do with building it like logging what I just did and saving some of your data in a cookie and sending a mail to the administrator that you are the first visitor on this page ever, ...
You should decouple them. You have a few assumptions that I think are a bit strange. Let's start with them.
The main purpose of an incoming http request is to give back some html
I have built PHP backends that only return JSON, instead of HTML. I had a really strong border between back and front end. I only used the backend to give me data from the database, or add/edit data in the databse. The front end was just a PHP script that would build the pages any way i wanted.
Since it is the web there is in theory no use for setters since
everything can be injected in the constructor
You could use the constructor, but you don't have too. You can use setters. Dependency injection is actually just turning the flow around.
You are on the right track though. You want some class that is responsible for building your pages. So, make it only responsible for your building your pages, and take out the other responsibilities. Things like logging, authentication etc should be outside of that.
For instance if you want logging, you could have your builder create your page, and your logger could then listen to all the things your builder is doing (with the observer pattern for instance). So if your builder says: "i created the home page", you can log it with your logger, who is actually listening to your builder.
Authentication for instance should happen even before your builder starts. You don't want your builder to go to work if you can already figure out that a user is not supposed to be on a page. You could use a database for that, and whitelist any usertype/pagerequest combination.
Then for data handling, i would create a backend, that only handles requests that are supposed to give back data, or save it. The front end could then communicate to get it's content by pulling it.
I hope this clears up a few things, but I'll be happy to answer more indept questions.
I'm completely new to jQuery and Ajax, but I've managed to learn how to do the Hello World, populate a select tag, etc, etc...
Problem is, I don't like to use structural PHP. The way I learned I have to call some PHP file with $.getJSON and that file has to "echo" my result.
What I want is to be able to call a PHP file that is actually a class with some methods and the return of the method would be what JavaScript would receive instead of just an echo result.
Thanks for your attention.
Ps.: I have a lot of experience with PHP-OOP and Flex+PHP using Amfphp. I'm trying to build a different version of view and I would like to re-use the classes that Flex already use.
jQuery runs on your computer, and PHP runs on the server. PHP and jQuery can only communicate via a series of well-crafted strings. On the server, you are free to create objects, run methods, manipulate output, and anything else. However, if you're going to be feeding that data back into your jQuery application (still running on the client's machine), you'll need to echo (or output) the results of your PHP script.
You may consider something like this:
$.post('server.php', { 'class':'foo', 'method':'bar' }, function( response ) {
/* do something with the output of $foo->bar(); */
});
As you can see here, I can define the class and method I'd like to have called on the server. From server.php, we would look to $_POST['class'] and $_POST['method'] to determine what we will instantiate, and which methods we will run.
The AMF is somehow different from HTTP, they're different protocols.
When using AJAX (jQuery or not), you're calling HTTP methods on URIs, not OOP methods. So everything ends up in a minimum of two mappings:
Your application logic mapped to methods and URIs.
Your Javascript code mapped to methods and URIs.
Here is a sample using Respect\Rest:
$router->get('/users/*', function($userName) {
return MyDatabaseLayer::fetchUser($userName); //Illustrative
})->accept(
'application/json' => function($data) {
header('Content-type: application/json');
return json_encode($data);
}
);
Now the jQuery part:
$.getJSON('/users/alganet', function(user) {
alert(user.name);
});
You should use appropriate HTTP methods for different actions. Saving an user would be something like:
$router->post('/users/*', function($userName) {
return MyDatabaseLayer::saveUser($_POST['user']); //Illustrative
});
jQuery:
$.post('/users', $("$userform").serialize());
There are four main HTTP methods: GET, POST, PUT and DELETE. GET and POST are the most common ones.
There is a nice trivia: Both HTTP, REST and AMF were written by the same guy: Roy Fielding.
I'm working on converting my standard PHP project to OOP but I ran into a wall about how to handle AJAX calls with PHP Classes. I'm not happy with the way I'm doing this now. I have a TillAjax.php file which I call from my TillUI.php file from a AJAX call.
In the TillAjax.php file I do this to get the information passed from the ajax call.
$till = new Till();
if(isset($_POST['data']))
$till->doStuff($_POST['data']);
I think this ruins the OOP.
I have worked with ASP.NET MVC and here its possible to call a specific action in a controller without i have to check for the post value. So I want to know if there is a smarter PHP way to solve the above problem?
The method I use for this is to have an Ajax class.
Your php file calls Ajax::Process($_GET['handle']), where 'handle' contains the name of a static class method, so perhaps 'Till::Process'. The Ajax class checks the function against a list of permitted functions (i.e. functions that you are allowing to be called via ajax), and then uses call_user_func_array to call the function (my code uses the contents of $_POST as arguments to pass to the function). The return of that function is automatically encoded as json and outputted to the client.
This means that your target php file looks like this:
<?php
//File: ajax.php
include ("Ajax.php");
Ajax::Process($_GET['handle']);
?>
Which I think is pretty simple.
Then you can have javascript that looks like this (jquery) :
$.get('ajax.php?handle=Till::Process', {}, function(result) {
//called on page response
});
So then result now contains whatever data is returned from the php method Till::Process.
Have you considered using a PHP MVC framework such as CodeIgniter, CakePHP, Kohana, etc? They will let you route requests to specific controller methods. It will be a much cleaner solution if migrating to one of these frameworks is an option for you.
I'm currently working on a small application that works like this:
When the user clicks a link, an Ajax GET request is fired.
The request hits a server-side PHP script.
The script, which requests information for another domain, retrieves a JSON feed.
The feed is then echoed back to the client for parsing.
I'm not really a PHP developer, so I am looking for some best practices with respect to cross-domain requests. I'm currently using file_get_contents() to retrieve the JSON feed and, although it's functional, it seems like a weak solution.
Does the PHP script do anything other than simply call the other server? Do you have control over what the other server returns? If the answers are No and Yes, you could look into JSONP.
You might want to abstract the retrieval process in PHP with an interface so you can swap out implementations if you need too. Here is a naive example:
interface CrossSiteLoader
{
public function loadURL($url);
}
class SimpleLoader implements CrossSiteLoader
{
public function loadURL($url)
{
return file_get_contents($url);
}
}
Comes in handy if you need to test locally with your own data because you can use a test implementation:
public ArrayLoader implements CrossSiteLoader
{
public function loadURL($url)
{
return json_encode(array('var1' => 'value1', 'var2' => 'value2'));
}
}
or if you just want to change from file_get_contents to something like curl
How should I write error reporting modules in PHP?
Say, I want to write a function in PHP: 'bool isDuplicateEmail($email)'.
In that function, I want to check if the $email is already present in the database.
It will return 'true', if exists. Else 'false'.
Now, the query execution can also fail, In that time I want to report 'Internal Error' to the user.
The function should not die with typical mysql error: die(mysql_error(). My web app has two interfaces: browser and email(You can perform certain actions by sending an email).
In both cases it should report error in good aesthetic.
Do I really have to use exception handling for this?
Can anyone point me to some good PHP project where I can learn how to design robust PHP web-app?
In my PHP projects, I have tried several different tacts. I've come to the following solution which seems to work well for me:
First, any major PHP application I write has some sort of central singleton that manages application-level data and behaviors. The "Application" object. I mention that here because I use this object to collect generated feedback from every other module. The rendering module can query the application object for the feedback it deems should be displayed to the user.
On a lower-level, every class is derived from some base class that contains error management methods. For example an "AddError(code,string,global)" and "GetErrors()" and "ClearErrors". The "AddError" method does two things: stores a local copy of that error in an instance-specific array for that object and (optionally) notifies the application object of this error ("global" is a boolean) which then stores that error for future use in rendering.
So now here's how it works in practice:
Note that 'Object' defines the following methods: AddError ClearErrors GetErrorCodes GetErrorsAsStrings GetErrorCount and maybe HasError for convenience
// $GLOBALS['app'] = new Application();
class MyObject extends Object
{
/**
* #return bool Returns false if failed
*/
public function DoThing()
{
$this->ClearErrors();
if ([something succeeded])
{
return true;
}
else
{
$this->AddError(ERR_OP_FAILED,"Thing could not be done");
return false;
}
}
}
$ob = new MyObject();
if ($ob->DoThing())
{
echo 'Success.';
}
else
{
// Right now, i may not really care *why* it didn't work (the user
// may want to know about the problem, though (see below).
$ob->TrySomethingElse();
}
// ...LATER ON IN THE RENDERING MODULE
echo implode('<br/>',$GLOBALS['app']->GetErrorsAsStrings());
The reason I like this is because:
I hate exceptions because I personally believe they make code more convoluted that it needs to be
Sometimes you just need to know that a function succeeded or failed and not exactly what went wrong
A lot of times you don't need a specific error code but you need a specific error string and you don't want to create an error code for every single possible error condition. Sometimes you really just want to use an "opfailed" code but go into some detail for the user's sake in the string itself. This allows for that flexibility
Having two error collection locations (the local level for use by the calling algorithm and global level for use by rendering modules for telling the user about them) has really worked for me to give each functional area exactly what it needs to get things done.
Using MVC, i always use some sort of default error/exception handler, where actions with exceptions (and no own error-/exceptionhandling) will be caught.
There you could decide to answer via email or browser-response, and it will always have the same look :)
I'd use a framework like Zend Framework that has a thorough exception handling mechanism built all through it.
Look into exception handling and error handling in the php manual. Also read the comments at the bottom, very useful.
There's aslo a method explained in those page how to convert PHP errors into exceptions, so you only deal with exceptions (for the most part).