I am working on a web application that will make extensive use of AJAX techniques for client/server communication...JSON-RPC specifically. Zend Framework is being used server-side, and it offers a nice JSON-RPC server that I would like to use.
My goal is to architect a maintainable system that exposes a large subset of server-side functionality to the client-side (javascript), without unnecessary code duplication. I've seen numerous blog posts and tutorials on how to use ZF's JSON-RPC server (see here and here), but they all seemed geared towards exposing a small, publicly consumable API. Code duplication is common, for example one blog post has the following method exposed:
public static function setTitle($bookId, $title) {
$book = new Nickel_Model_Book($bookId);
$book->setTitle($title);
$book->update();
return true;
}
I don't like the fact that there are two setTitle
methods. If the method signature for one changes, the other has to be kept in sync...seems like a maintainability nightmare if your API is extensive. It seems to me that there should be one Book
class, with one setTitle
method.
My initial thought is add a docblock annotation @export
to methods/classes that I want exposed. When I decide to expose the setTitle
method, I just add the annotation rather than a new method.
One potential problem I see involves object persistence. Server-side, it makes sense for setTitle
to set the object's title property...but not persist it in the database until update()
is called. Client-side, calling setTitle
should immediately affect the database. One potential solution is to modify all accessors such that they take a optional second parameter signifying the modification should update the database immediately:
function setTitle($title, $persist = false) {
$this->title = $title;
if ($persist) $this->update();
}
Some sort of proxy class could ensure that the $persist
flag is set for all client-side RPC invocations.
Another problem is the serialization of PHP objects. Server-side, it makes sense to do a OO-style $book->setTitle("foo")
call, but client-side book.setTitle(1234, "foo")
makes sense (where 1234 is the book's ID) due to the lack of state. My solution for this would be to have the aforementioned proxy class be responsible for somehow turning book.setTitle(1234, "foo")
into:
$book = new Book();
$book->load(1234);
return $book->setTitle($title);
I feel like this problem must have been tackled or discussed before...but I'm not finding many resources online. Does this seem like a sane solution?
What you're looking for is called Service Layer.
Their entities should be purely data containers (unless you're using Active Record), you should only expose your service layer, and this in turn accesses their entities and their respective methods.
Your class of service would be something like this:
class BookService extends Service {
//...
public function changeBookTitle( $title, Book $book )
{
//verify if the $title is correct and valid
$book->setTitle( $title );
$this->methodToGetThePersistenceManager()->save( $book );
//fire events, create a result object, etc...
}
}
I was mulling over your question for a few minutes. If you want to try, and it's in PHP, you could make some magic methods of the form
set{Property}of{Object}.
You can do this through the magic __call method.
That way you wouldn't have to explicitly define the methods but the properties would still get set.
The magic method would identify which type of object it has to instantiate and which property to set on it and then persist.
You'd have to find some way of differentiating between remote calls and local calls though so you don't persist by mistake if you're making local library calls and that you do persist on remote calls.
I feel like I misunderstood your question somehow but I tried.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With