-- Serkan Temizel <[email protected]> wrote (on Wednesday, 23 February 2011, 06:09 PM +0200): > After a question about sending mail from controller or model (it is > here<http://zend-framework-community.634137.n4.nabble.com/send-mail-notices-from-the-controller-or-model-td3319085.html>*) > I got some unexpected answers. Jurian mentioned about a service approach. > After this post I made some search about services and found this > article<http://www.angryobjects.com/2009/03/30/writing-robust-php-backends-with-zend-framework/>** > > Leendert Brouwer's article was on something totally new for me. Because it > was adding a new layer to MVC, a service layer. domain objects and mappers > are also new to me. > > I searched the web for documents about this new concept but I found nearly > no helpful resource. > > I need some valuable resource and coding and structuring samples about this > approach.
Martin Fowler's "Patterns of Enterprise Application Architecture" has a section on Service Layers. I've also spoken about them a number of times in several presentations I've done (http://slideshare.net/weierophinney). Basically, think of the Service Layer object as the public API of your application or resource: these are the things you can do. As a quick pseudo-code example: class BlogResource { public function create($data) public function fetch($id) public function update($id, $data) public function delete($id) public function fetchRecent() public function fetchByYear($year) public function fetchByMonth($month, $year) public function fetchByDay($day, $month, $year) public function fetchByTag($tag) } I typically also compose something like the new ZF2 EventManager or a pubsub implementation of some sort, which allows me to tie into specific actions in order to introduce such things as ACL checks, etc. The service object then takes care of interacting with my various domain entities, mappers, etc. Your MVC application then is simply passing input to the service object, and handing the response off to the presentation layer. As an example: class BlogController extends Zend_Rest_Controller { public function init() { $this->resource = new BlogResource(); // optionally configure this: inject the data access layer // and/or mapper, tie in event handlers, etc. } public function indexAction() { $this->view->entries = $this->resource->fetchRecent(); } public function getAction() { if (!$id = $this->getRequest()->getQuery('id', false)) { throw new DomainException('Missing identifier'); } $this->view->entry = $this->resource->fetch($id); } public function postAction() { if (!$data = $this->getRequest()->getPost('entry', false)) { throw new DomainException('Missing data; cannot create entry'); } $this->view->entry = $this->resource->create($data); } public function putAction() { if (!$id = $this->getRequest()->getQuery('id', false)) { throw new DomainException('Missing identifier; cannot update'); } if (!$data = $this->getRequest()->getPost('entry', false)) { throw new DomainException('Missing data; cannot update entry'); } $this->view->entry = $this->resource->update($id, $data); } public function deleteAction() { if (!$id = $this->getRequest()->getQuery('id', false)) { throw new DomainException('Missing identifier; cannot delete'); } $this->view->status = $this->resource->delete($id); } public function fetchByYearAction() { $year = $this->getQuery('year', date('Y')); $this->view->entries = $this->resource->fetchByYear($year); } // etc... } You'll notice that the individual action methods are succinct, and simply proxy to the service object, after first marshalling the input. Later, you can hook the same service object up to one of the server classes: $json = new Zend_Json_Server(); $json->setClass($blogResource, 'blog'); $response = $json->handle(); echo $response; Basically, you're writing a re-usable application layer that simply needs something to provide input, and another layer to produce the presentation. > More importantly I need your opinions about this approach. Why ZF > don't ship with a service layer or default mapper? Are they really > needed or they just increase the complexity? We don't ship a mapper because, frankly, ORM solutions are the sort of thing that need entire teams to get right, and there's a great solution out there already: Doctrine 2. Regarding a service layer, we can't really ship a service layer by default -- service layers are highly application-specific (as is the entire domain model). About the most we could likely ship is an interface for RESTful resources, and a "base controller" for RESTful resources that expects to instantiate a RESTful resource and which would provide the basic functionality as outlined in the controller above (this would be for basic CRUD operations only). I'm definitely considering this for ZF2, as it would streamline many common workflows -- but you'd still be responsible for writing the various domain entities, wiring in an ORM (if used), etc. -- Matthew Weier O'Phinney Project Lead | [email protected] Zend Framework | http://framework.zend.com/ PGP key: http://framework.zend.com/zf-matthew-pgp-key.asc
