Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge remote branch 'jwage/master'

Conflicts:
	README.markdown
  • Loading branch information...
commit f412f9966b4ea750029f2222fbca133b4c8b2ab4 2 parents 55e4bbc + 1725df8
@jwage jwage authored
View
101 README.markdown
@@ -8,4 +8,103 @@ http://github.com/doctrine/rest/tree/master/lib/Doctrine/REST/Server/README.mark
Interact with any RESTful resource via an ActiveRecord style implementation.
-http://github.com/doctrine/rest/tree/master/lib/Doctrine/REST/Client/README.markdown
+<<<<<<< HEAD
+http://github.com/doctrine/rest/tree/master/lib/Doctrine/REST/Client/README.markdown
+=======
+ $person = Person::find(1); // GET http://api.people.com/person/1.xml
+
+Now we can change some properties of that person:
+
+ $person->setName('Jonathan H. Wage');
+
+Once we're done we can simply save it and the appropriate REST call will be made:
+
+ $person->save(); // POST http://api.people.com/person/1.xml (name=Jonathan H. Wage)
+
+## Client
+
+The REST client is an ActiveRecord style implementation for working with REST
+services. All you need to do is define some PHP classes that are mapped to some
+REST service on the web. Here is an example where we map a Person to
+http://api.people.com/person:
+
+ <?php
+
+ namespace Entities;
+
+ use Doctrine\REST\Client\Entity;
+
+ class Person extends Entity
+ {
+ private $id;
+ private $name;
+
+ public static function configure(EntityConfiguration $entityConfiguration)
+ {
+ $entityConfiguration->setUrl('http://api.people.com');
+ $entityConfiguration->setName('person');
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+ }
+
+Now when we perform some actions it will generate the appropriate REST request,
+execute it, transform the response and hydrate the results to your PHP objects.
+
+ $person = new Person();
+ $person->setName('Jonathan H. Wage');
+ $person->save(); // PUT http://api.people.com/person.xml (name=Jonathan H. Wage)
+
+We can retrieve that person again now:
+
+ $person = Person::find($person->getId()); // GET http://api.people.com/person/1.xml
+
+Or you can retrieve all Person objects:
+
+ $persons = Person::findAll();
+
+## Server
+
+The Doctrine 2 REST server allows you to easily expose your entities through some
+REST services. This is the raw low level server and does not include any routing
+or URL parsing so you would need to implement in some existing framework that
+has routing like Symfony or Zend Framework.
+
+All you need to do is create a new REST server instance and pass it the instance
+of your EntityManager you want to expose the entities for and an array representing
+the server request you want to process:
+
+ $request = array(
+ '_method' => 'get',
+ '_format' => 'xml',
+ '_entity' => 'user',
+ '_action' => 'get',
+ '_id' => 1
+ );
+
+ $server = new \Doctrine\REST\Server\Server($em, $request);
+ $server->setEntityAlias('Entities\User', 'user');
+
+ $xml = $server->execute();
+
+The above would retrieve the User with the id of 1 and return an XML document
+like the following:
+
+ <user>
+ <id>1</id>
+ <username>jwage</username>
+ </user>
+>>>>>>> jwage/master
View
38 client.php
@@ -0,0 +1,38 @@
+<?php
+
+require '/Users/jwage/Sites/doctrine2git/lib/Doctrine/Common/ClassLoader.php';
+
+use Doctrine\REST\Client\Client,
+ Doctrine\REST\Client\EntityConfiguration,
+ Doctrine\REST\Client\Manager,
+ Doctrine\REST\Client\Entity,
+ Doctrine\Common\ClassLoader;
+
+$classLoader = new ClassLoader('Doctrine\REST', __DIR__ . '/lib');
+$classLoader->register();
+
+$client = new Client();
+
+$manager = new Manager($client);
+$manager->registerEntity('User');
+
+Entity::setManager($manager);
+
+class User extends Entity
+{
+ public $id;
+ public $username;
+ public $password;
+
+ public static function configure(EntityConfiguration $entityConfiguration)
+ {
+ $entityConfiguration->setUrl('http://localhost/rest/server.php');
+ $entityConfiguration->setName('user');
+ }
+}
+
+$user = User::find(9);
+$user->username = 'teetertertsting';
+$user->password = 'w00t';
+$user->save();
+print_r($user);
View
74 js/example.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>jAct demo</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
+ <script src="jActiveResource.js"></script>
+
+ <script>
+ function loadEditForm(id) {
+ User.find(id, function(user) {
+ $('#identifier').attr('value', user.id);
+ $('#username').attr('value', user.username);
+ $('#password').attr('value', user.username);
+ });
+ }
+
+ $(function() {
+ jActiveResource.define('User', {
+ url: 'http://localhost/rest/server.php/user',
+
+ username: null,
+ password: null,
+
+ toString: function () {
+ return 'username=' + this.username + '&password=' + this.password;
+ }
+ });
+
+ User.findAll(null, function(users) {
+ for (var i in users) {
+ user = users[i];
+ $('#users').append('<li id="user_' + user.id + '">' + user.id + ': ' + user.username + ' <a href="javascript: loadEditForm(' + user.id + ');">Edit</a> | <a href="javascript: UserFactory.destroy(' + user.id + ', function(data) { $(\'#user_\' + ' + user.id + ').remove(); });">Delete</a></li>');
+ }
+ });
+
+ $('#create_user').submit(function(data) {
+ var user = User.create();
+
+ user.id = $('#identifier').attr('value');
+ user.username = $('#username').attr('value');
+ user.password = $('#password').attr('value');
+
+ user.save(function (user) {
+ if ($('#user_' + user.id).length) {
+ $('#user_' + user.id).after('<li id="user_' + user.id + '">' + user.id + ': ' + user.username + ' <a href="javascript: loadEditForm(' + user.id + ');">Edit</a> | <a href="javascript: UserFactory.destroy(' + user.id + ', function(data) { $(\'#user_\' + ' + user.id + ').remove(); });">Delete</a></li>').remove();
+ } else {
+ $('#users').append('<li id="user_' + user.id + '">' + user.id + ': ' + user.username + ' <a href="javascript: loadEditForm(' + user.id + ');">Edit</a> | <a href="javascript: UserFactory.destroy(' + user.id + ', function(data) { $(\'#user_\' + ' + user.id + ').remove(); });">Delete</a></li>');
+ }
+ });
+
+ return false;
+ });
+ });
+ </script>
+
+ </head>
+ <body>
+
+ <h2>Create User</h3>
+ <form id="create_user">
+ <input type="hidden" name="identifier" id="identifier" />
+ Username: <input type="text" id="username" name="username" /><br/>
+ Password: <input type="password" id="password" name="password" /><br/>
+ <input type="submit" name="save" value="Save" />
+ </form>
+
+ <h2>Users</h2>
+ <ul id="users">
+
+ </ul>
+
+ </body>
+</html>
View
61 js/jActiveResource.js
@@ -0,0 +1,61 @@
+var jActiveResource = jQuery.extend({
+ create: function() {
+ return jQuery.extend(this);
+ },
+
+ define: function (name, definition) {
+ var instance = jQuery.extend(this, definition);
+ eval(name + ' = instance;');
+ eval(name + 'Factory = jQuery.extend(jActiveResourceFactory);')
+ },
+
+ find: function(id, callback) {
+ this.execute('get', this.getUrl(id), null, callback);
+ },
+
+ findAll: function(data, callback) {
+ this.execute('get', this.getUrl(), data, callback);
+ },
+
+ destroy: function(id, callback) {
+ this.execute('delete', this.getUrl(this.id), null, callback);
+ },
+
+ save: function(callback) {
+ this.execute('post', this.getUrl(this.id), this.toString(), callback);
+ },
+
+ getUrl: function(id, action, parameters) {
+ if (id) {
+ return this.url + '/' + id + '.json';
+ } else {
+ return this.url + '.json';
+ }
+ },
+
+ execute: function(method, url, data, callback) {
+ $.ajax({
+ type: method,
+ dataType: 'json',
+ url: url,
+ data: data,
+ success: function(data) {
+ if (data.length > 0) {
+ var results = new Array();
+ for (i = 0; i < data.length; i++) {
+ results[i] = jQuery.extend(this.prototype, data[i]);
+ }
+ callback(results)
+ } else {
+ callback(jQuery.extend(this.prototype, data));
+ }
+ }
+ });
+ }
+});
+
+var jActiveResourceFactory = jActiveResource.extend({
+ destroy: function(id, callback) {
+ this.execute('delete', this.getUrl(id), null, callback);
+ }
+});
View
5 lib/Doctrine/REST/Client/Client.php
@@ -78,16 +78,13 @@ public function execute(Request $request)
switch ($request->getMethod()) {
case self::POST:
+ case self::PUT:
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request->getParameters()));
break;
case self::DELETE:
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
- case self::PUT:
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request->getParameters()));
- break;
case self::GET:
default:
break;
View
83 lib/Doctrine/REST/Server/Action/AbstractAction.php
@@ -21,7 +21,8 @@
namespace Doctrine\REST\Server\Action;
-use \Doctrine\REST\Server\RequestHandler;
+use Doctrine\REST\Server\RequestHandler,
+ Doctrine\ORM\EntityManager;
/**
* Abstract server action class for REST server actions to extend from.
@@ -35,21 +36,32 @@
abstract class AbstractAction
{
protected $_requestHandler;
- protected $_em;
+ protected $_source;
protected $_request;
public function __construct(RequestHandler $requestHandler)
{
$this->_requestHandler = $requestHandler;
- $this->_em = $requestHandler->getEntityManager();
+ $this->_source = $requestHandler->getSource();
$this->_request = $requestHandler->getRequest();
}
- abstract public function execute();
+ public function executeORM()
+ {
+ }
+
+ public function executeDBAL()
+ {
+ }
+
+ protected function _getEntity()
+ {
+ return $this->_requestHandler->getEntity();
+ }
- protected function _resolveEntityAlias($alias)
+ protected function _getEntityIdentifierKey()
{
- return $this->_requestHandler->resolveEntityAlias($alias);
+ return $this->_requestHandler->getEntityIdentifierKey($this->_getEntity());
}
protected function _setQueryFirstAndMax($q)
@@ -61,31 +73,60 @@ protected function _setQueryFirstAndMax($q)
if (isset($this->_request['_page'])) {
$page = $this->_request['_page'];
$first = ($page - 1) * $maxPerPage;
- $q->setFirstResult($first);
- $q->setMaxResults($maxPerPage);
} else {
if (isset($this->_request['_first'])) {
- $q->setFirstResult($this->_request['_first']);
+ $first = $this->_request['_first'];
} else {
- $q->setFirstResult(0);
+ $first = 0;
}
if (isset($this->_request['_max'])) {
- $q->setMaxResults($this->_request['_max']);
- } else {
- $q->setMaxResults($maxPerPage);
+ $maxPerPage = $this->_request['_max'];
}
}
+
+ if ($this->_source instanceof EntityManager) {
+ $q->setFirstResult($first);
+ $q->setMaxResults($maxPerPage);
+ } else {
+ $platform = $this->_source->getDatabasePlatform();
+ return $platform->modifyLimitQuery($q, $maxPerPage, $first);
+ }
}
- protected function _getFindByIdQuery($entity, $id)
+ protected function _findEntityById()
{
- $qb = $this->_em->createQueryBuilder()
- ->select('a')
- ->from($entity, 'a')
- ->where('a.id = ?1')
- ->setParameter('1', $id);
- $q = $qb->getQuery();
- return $q;
+ if ($this->_source instanceof EntityManager) {
+ $entity = $this->_getEntity();
+ $id = $this->_request['_id'];
+
+ $qb = $this->_source->createQueryBuilder()
+ ->select('a')
+ ->from($entity, 'a')
+ ->where('a.id = ?1')
+ ->setParameter('1', $id);
+ $query = $qb->getQuery();
+
+ return $query->getSingleResult();
+ } else {
+ $entity = $this->_getEntity();
+ $identifierKey = $this->_getEntityIdentifierKey($entity);
+
+ $query = sprintf('SELECT * FROM %s WHERE %s = ?', $entity, $identifierKey);
+
+ return $this->_source->fetchRow($query, array($this->_request['_id']));
+ }
+ }
+
+ protected function _updateEntityInstance($entity)
+ {
+ $data = $this->_gatherData($this->_request->getData());
+ foreach ($data as $key => $value) {
+ $setter = 'set' . ucfirst($key);
+ if (is_callable(array($entity, $setter))) {
+ $entity->$setter($value);
+ }
+ }
+ return $entity;
}
protected function _gatherData()
View
48 lib/Doctrine/REST/Server/Action/AbstractSaveAction.php
@@ -1,48 +0,0 @@
-<?php
-/*
- * $Id$
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This software consists of voluntary contributions made by many individuals
- * and is licensed under the LGPL. For more information, see
- * <http://www.doctrine-project.org>.
-*/
-
-namespace Doctrine\REST\Server\Action;
-
-use \Doctrine\REST\Server\RequestHandler;
-
-/**
- * Abstract class for insert and update server actions to extend from.
- *
- * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
- * @link www.doctrine-project.org
- * @since 2.0
- * @version $Revision$
- * @author Jonathan H. Wage <jonwage@gmail.com>
- */
-abstract class AbstractSaveAction extends AbstractAction
-{
- protected function _updateEntityInstance($entity)
- {
- $data = $this->_gatherData($this->_request->getData());
- foreach ($data as $key => $value) {
- $setter = 'set' . ucfirst($key);
- if (is_callable(array($entity, $setter))) {
- $entity->$setter($value);
- }
- }
- return $entity;
- }
-}
View
24 lib/Doctrine/REST/Server/Action/DeleteAction.php
@@ -32,18 +32,22 @@
*/
class DeleteAction extends AbstractAction
{
- public function execute()
+ public function executeORM()
{
- $query = $this->_getFindByIdQuery(
- $this->_resolveEntityAlias($this->_request['_entity']),
- $this->_request['_id']
- );
- $entity = $query->getSingleResult();
+ if ($entity = $this->_findEntityById()) {
+ $this->_source->remove($entity);
+ $this->_source->flush();
+ return $entity;
+ }
+ }
- if ($entity) {
- $this->_em->remove($entity);
- $this->_em->flush();
+ public function executeDBAL()
+ {
+ if ($entity = $this->_findEntityById()) {
+ $this->_source->delete($this->_getEntity(), array(
+ $this->_getEntityIdentifierKey() => $this->_request['_id']
+ ));
+ return $entity;
}
- return $entity;
}
}
View
15 lib/Doctrine/REST/Server/Action/GetAction.php
@@ -34,17 +34,12 @@ class GetAction extends AbstractAction
{
public function execute()
{
- $query = $this->_getFindByIdQuery(
- $this->_resolveEntityAlias($this->_request['_entity']),
- $this->_request['_id']
- );
- $this->_setQueryFirstAndMax($query);
+ $entity = $this->_findEntityById();
- $result = $query->getSingleResult();
-
- if ( ! $result) {
- throw new \InvalidArgumentException(sprintf('Could not find the "%s" with an ids of "%s"', $this->_request['_entity'], implode(', ', (array) $this->_request['_id'])));
+ if ( ! $entity) {
+ throw new \InvalidArgumentException(sprintf('Could not find the "%s" with an id of "%s"', $this->_request['_entity'], implode(', ', (array) $this->_request['_id'])));
}
- return $result;
+
+ return $entity;
}
}
View
34 lib/Doctrine/REST/Server/Action/InsertAction.php
@@ -30,16 +30,34 @@
* @version $Revision$
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
-class InsertAction extends AbstractSaveAction
+class InsertAction extends AbstractAction
{
- public function execute()
+ public function executeORM()
{
- $entityName = $this->_resolveEntityAlias($this->_request['_entity']);
- $entity = new $entityName();
- $this->_updateEntityInstance($entity);
- $this->_em->persist($entity);
- $this->_em->flush();
+ $entity = $this->_getEntity();
- return $entity;
+ $instance = new $entity();
+ $this->_updateEntityInstance($instance);
+ $this->_source->persist($instance);
+ $this->_source->flush();
+
+ return $instance;
+ }
+
+ public function executeDBAL()
+ {
+ $entity = $this->_getEntity();
+ $identifierKey = $this->_getEntityIdentifierKey();
+
+ $data = $this->_gatherData();
+
+ unset($data['id']);
+ $this->_source->insert($entity, $data);
+ $data = array_merge(
+ array($identifierKey => $this->_source->lastInsertId()),
+ $data
+ );
+
+ return $data;
}
}
View
32 lib/Doctrine/REST/Server/Action/ListAction.php
@@ -32,11 +32,12 @@
*/
class ListAction extends AbstractAction
{
- public function execute()
+ public function executeORM()
{
- $qb = $this->_em->createQueryBuilder()
+ $entity = $this->_getEntity();
+ $qb = $this->_source->createQueryBuilder()
->select('a')
- ->from($this->_resolveEntityAlias($this->_request['_entity']), 'a');
+ ->from($entity, 'a');
$data = $this->_gatherData();
foreach ($data as $key => $value) {
@@ -46,7 +47,28 @@ public function execute()
$query = $qb->getQuery();
$this->_setQueryFirstAndMax($query);
- $collection = $query->execute();
- return $collection;
+ $results = $query->execute();
+
+ return $results;
+ }
+
+ public function executeDBAL()
+ {
+ $entity = $this->_getEntity();
+
+ $params = array();
+ $query = sprintf('SELECT * FROM %s', $entity);
+ if ($data = $this->_gatherData()) {
+ $query .= ' WHERE ';
+ foreach ($data as $key => $value) {
+ $query .= $key . ' = ? AND ';
+ $params[] = $value;
+ }
+ $query = substr($query, 0, strlen($query) - 5);
+ }
+ $query = $this->_setQueryFirstAndMax($query);
+ $results = $this->_source->fetchAll($query, $params);
+
+ return $results;
}
}
View
21 lib/Doctrine/REST/Server/Action/UpdateAction.php
@@ -30,15 +30,28 @@
* @version $Revision$
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
-class UpdateAction extends AbstractSaveAction
+class UpdateAction extends AbstractAction
{
- public function execute()
+ public function executeORM()
{
- if ($entity = $this->_em->find($this->_resolveEntityAlias($this->_request['_entity']), $this->_request['_id'])) {
+ if ($entity = $this->_findEntityById()) {
$this->_updateEntityInstance($entity);
- $this->_em->flush();
+ $this->_source->flush();
}
return $entity;
}
+
+ public function executeDBAL()
+ {
+ $entity = $this->_getEntity();
+ $identifierKey = $this->_getEntityIdentifierKey($entity);
+
+ $data = $this->_gatherData();
+ $this->_source->update($entity, $data, array(
+ $identifierKey => $this->_request['_id']
+ ));
+
+ return $this->_findEntityById();
+ }
}
View
50 lib/Doctrine/REST/Server/PHPRequestParser.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Doctrine\REST\Server;
+
+class PHPRequestParser
+{
+ public function getRequestArray()
+ {
+ $path = $_SERVER['PATH_INFO'];
+ $path = ltrim($path, '/');
+ $e = explode('/', $path);
+ $count = count($e);
+ $end = end($e);
+ $e2 = explode('.', $end);
+ $e[count($e) - 1] = $e2[0];
+ $format = isset($e2[1]) ? $e2[1] : 'xml';
+ $entity = $e[0];
+ $id = isset($e[1]) ? $e[1] : null;
+ $action = isset($e[2]) ? $e[2] : null;
+ $method = isset($_REQUEST['_method']) ? $_REQUEST['_method'] : $_SERVER['REQUEST_METHOD'];
+ $method = strtoupper($method);
+
+ if ($count === 1) {
+ if ($method === 'POST' || $method === 'PUT') {
+ $action = 'insert';
+ } else if ($method === 'GET') {
+ $action = 'list';
+ }
+ } else if ($count === 2) {
+ if ($method === 'POST' || $method === 'PUT') {
+ $action = 'update';
+ } else if ($method === 'GET') {
+ $action = 'get';
+ } else if ($method === 'DELETE') {
+ $action = 'delete';
+ }
+ } else if ($count === 3) {
+ $action = $action;
+ }
+
+ $data = array_merge(array(
+ '_entity' => $entity,
+ '_id' => $id,
+ '_action' => $action,
+ '_format' => $format
+ ), $_REQUEST);
+
+ return $data;
+ }
+}
View
112 lib/Doctrine/REST/Server/RequestHandler.php
@@ -21,7 +21,8 @@
namespace Doctrine\REST\Server;
-use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityManager,
+ Doctrine\DBAL\Connection;
/**
* Class responsible for transforming a REST server request to a response.
@@ -34,13 +35,13 @@
*/
class RequestHandler
{
- private $_em;
+ private $_source;
private $_request;
private $_response;
private $_username;
private $_password;
private $_credentialsCallback;
- private $_entityAliases = array();
+ private $_entities = array();
private $_actions = array(
'delete' => 'Doctrine\\REST\\Server\\Action\\DeleteAction',
@@ -50,25 +51,46 @@ class RequestHandler
'list' => 'Doctrine\\REST\\Server\\Action\\ListAction'
);
- public function __construct(EntityManager $em, Request $request, Response $response)
+ public function __construct($source, Request $request, Response $response)
{
- $this->_em = $em;
+ $this->_source = $source;
$this->_request = $request;
$this->_response = $response;
$this->_response->setRequestHandler($this);
$this->_credentialsCallback = array($this, 'checkCredentials');
}
- public function addEntityAlias($entity, $alias)
+ public function configureEntity($entity, $configuration)
{
- $this->_entityAliases[$alias] = $entity;
+ $this->_entities[$entity] = $configuration;
+ }
+
+ public function setEntityAlias($entity, $alias)
+ {
+ $this->_entities[$entity]['alias'] = $alias;
+ }
+
+ public function addEntityAction($entity, $action, $className)
+ {
+ $this->_entities[$entity]['actions'][$action] = $className;
+ }
+
+ public function setEntityIdentifierKey($entity, $identifierKey)
+ {
+ $this->_entities[$entity]['identifierKey'] = $identifierKey;
+ }
+
+ public function getEntityIdentifierKey($entity)
+ {
+ return isset($this->_entities[$entity]['identifierKey']) ? $this->_entities[$entity]['identifierKey'] : 'id';
}
public function resolveEntityAlias($alias)
{
- if (isset($this->_entityAliases[$alias]))
- {
- return $this->_entityAliases[$alias];
+ foreach ($this->_entities as $entity => $configuration) {
+ if (isset($configuration['alias']) && $configuration['alias'] === $alias) {
+ return $entity;
+ }
}
return $alias;
}
@@ -132,9 +154,9 @@ public function getActions()
return $this->_actions;
}
- public function getEntityManager()
+ public function getSource()
{
- return $this->_em;
+ return $this->_source;
}
public function getRequest()
@@ -147,47 +169,51 @@ public function getResponse()
return $this->_response;
}
+ public function getEntity()
+ {
+ return $this->resolveEntityAlias($this->_request['_entity']);
+ }
+
public function execute()
{
try {
- $this->_executeAction();
+ $entity = $this->getEntity();
+ $actionInstance = $this->getAction($entity, $this->_request['_action']);
+
+ if (method_exists($actionInstance, 'execute')) {
+ $result = $actionInstance->execute();
+ } else {
+ if ($this->_source instanceof EntityManager) {
+ $result = $actionInstance->executeORM();
+ } else {
+ $result = $actionInstance->executeDBAL();
+ }
+ }
+
+ $this->_response->setResponseData(
+ $this->_transformResultForResponse($result)
+ );
} catch (\Exception $e) {
$this->_response->setError($this->_getExceptionErrorMessage($e));
}
return $this->_response;
}
- public function getAction($actionName)
+ public function getAction($entity, $actionName)
{
- if ( ! is_object($this->_actions[$actionName])) {
- $actionClassName = $this->_actions[$actionName];
- if (class_exists($actionClassName)) {
+ if (isset($this->_actions[$actionName])) {
+ if ( ! is_object($this->_actions[$actionName])) {
+ $actionClassName = $this->_actions[$actionName];
$this->_actions[$actionName] = new $actionClassName($this);
- } else {
- throw new \Exception(sprintf('Invalid action specified %s', $actionName));
}
+ return $this->_actions[$actionName];
}
- return $this->_actions[$actionName];
- }
-
- private function _executeAction()
- {
- $actionInstance = $this->getAction($this->_request['_action']);
-
- $result = $actionInstance->execute();
-
- if ($result !== false) {
- $this->_response->setResponseData(
- $this->_transformResultForResponse($result)
- );
- } else {
- $this->_response->setError(
- sprintf(
- 'An error occurred executing the action named "%s" with a request method of "%s."',
- $this->_request['_action'],
- $this->_request['_method']
- )
- );
+ if (isset($this->_entities[$entity]['actions'][$actionName])) {
+ if ( ! is_object($this->_entities[$entity]['actions'][$actionName])) {
+ $actionClassName = $this->_entities[$entity]['actions'][$actionName];
+ $this->_entities[$entity]['actions'][$actionName] = new $actionClassName($this);
+ }
+ return $this->_entities[$entity]['actions'][$actionName];
}
}
@@ -209,12 +235,12 @@ private function _transformResultForResponse($result, $array = null)
}
if (is_object($result)) {
$entityName = get_class($result);
- try {
- $class = $this->_em->getMetadataFactory()->getMetadataFor($entityName);
+ if ($this->_source instanceof EntityManager) {
+ $class = $this->_source->getMetadataFactory()->getMetadataFor($entityName);
foreach ($class->fieldMappings as $fieldMapping) {
$array[$fieldMapping['fieldName']] = $class->getReflectionProperty($fieldMapping['fieldName'])->getValue($result);
}
- } catch (\Exception $e) {
+ } else {
$vars = get_object_vars($result);
foreach ($vars as $key => $value) {
$array[$key] = $value;
View
17 lib/Doctrine/REST/Server/Response.php
@@ -84,12 +84,14 @@ public function getContent()
private function _sendHeaders()
{
- if ( ! isset($_SERVER['PHP_AUTH_USER'])) {
- header('WWW-Authenticate: Basic realm="Doctrine REST API"');
- header('HTTP/1.0 401 Unauthorized');
- } else {
- if ( ! $this->_requestHandler->hasValidCredentials()) {
- $this->setError('Invalid credentials specified.');
+ if ($this->_requestHandler->getUsername()) {
+ if ( ! isset($_SERVER['PHP_AUTH_USER'])) {
+ header('WWW-Authenticate: Basic realm="Doctrine REST API"');
+ header('HTTP/1.0 401 Unauthorized');
+ } else {
+ if ( ! $this->_requestHandler->hasValidCredentials()) {
+ $this->setError('Invalid credentials specified.');
+ }
}
}
@@ -116,6 +118,9 @@ private function _arrayToXml($array, $rootNodeName = 'doctrine', $xml = null, $c
}
foreach($array as $key => $value) {
+ if (is_numeric($key)) {
+ $key = $rootNodeName . $key;
+ }
$key = preg_replace('/[^A-Za-z_]/i', '', $key);
if (is_array($value) && ! empty($value)) {
View
21 lib/Doctrine/REST/Server/Server.php
@@ -21,7 +21,8 @@
namespace Doctrine\REST\Server;
-use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\EntityManager,
+ Doctrine\ORM\Connection;
/**
* Simple REST server facade.
@@ -38,11 +39,11 @@ class Server
private $_request;
private $_response;
- public function __construct(EntityManager $em, array $requestData = array())
+ public function __construct($source, array $requestData = array())
{
$this->_request = new Request($requestData);
$this->_response = new Response($this->_request);
- $this->_requestHandler = new RequestHandler($em, $this->_request, $this->_response);
+ $this->_requestHandler = new RequestHandler($source, $this->_request, $this->_response);
}
public function execute()
@@ -51,9 +52,14 @@ public function execute()
return $this->_requestHandler->getResponse()->getContent();
}
- public function addEntityAlias($entity, $alias)
+ public function setEntityIdentifierKey($entity, $identifierKey)
{
- $this->_requestHandler->addEntityAlias($entity, $alias);
+ $this->_requestHandler->setEntityIdentifierKey($entity, $identifierKey);
+ }
+
+ public function setEntityAlias($entity, $alias)
+ {
+ $this->_requestHandler->setEntityAlias($entity, $alias);
}
public function registerAction($action, $className)
@@ -61,6 +67,11 @@ public function registerAction($action, $className)
$this->_requestHandler->registerAction($action, $className);
}
+ public function addEntityAction($entity, $action, $className)
+ {
+ $this->_requestHandler->addEntityAction($entity, $action, $className);
+ }
+
public function setUsername($username)
{
$this->_requestHandler->setUsername($username);
View
42 server.php
@@ -0,0 +1,42 @@
+<?php
+
+use Doctrine\REST\Server\Server,
+ Doctrine\Common\ClassLoader;
+
+require '/Users/jwage/Sites/doctrine2git/lib/Doctrine/Common/ClassLoader.php';
+
+$classLoader = new ClassLoader('Doctrine\REST', __DIR__ . '/lib');
+$classLoader->register();
+
+$classLoader = new ClassLoader('Doctrine', '/Users/jwage/Sites/doctrine2git/lib');
+$classLoader->register();
+
+$config = new \Doctrine\ORM\Configuration();
+$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
+$config->setProxyDir('/tmp');
+$config->setProxyNamespace('Proxies');
+$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver());
+
+$connectionOptions = array(
+ 'driver' => 'pdo_mysql',
+ 'dbname' => 'rest_test',
+ 'user' => 'root'
+);
+
+$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
+
+$parser = new \Doctrine\REST\Server\PHPRequestParser();
+$requestData = $parser->getRequestArray();
+
+class TestAction
+{
+ public function executeDBAL()
+ {
+ return array('test' => 'test');
+ }
+}
+
+$server = new \Doctrine\REST\Server\Server($em->getConnection(), $requestData);
+$server->addEntityAction('user', 'test', 'TestAction');
+$server->execute();
+$server->getResponse()->send();
View
44 tests/Doctrine/Tests/REST/FunctionalTest.php
@@ -17,12 +17,13 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase
private $_manager;
private $_client;
- public function setUp()
+ public function setUpRest($type)
{
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
$config->setProxyDir('/tmp');
$config->setProxyNamespace('Proxies');
+ $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver());
$connectionOptions = array(
'driver' => 'pdo_sqlite',
@@ -36,7 +37,11 @@ public function setUp()
$schemaTool->dropSchema($classes);
$schemaTool->createSchema($classes);
- $this->_client = new TestFunctionalClient('user', $em);
+ if ($type === 'orm') {
+ $this->_client = new TestFunctionalClient('user', $em);
+ } else {
+ $this->_client = new TestFunctionalClient('user', $em->getConnection());
+ }
$this->_manager = new Manager($this->_client);
$this->_manager->registerEntity('Doctrine\Tests\REST\User');
@@ -44,7 +49,19 @@ public function setUp()
Entity::setManager($this->_manager);
}
- public function testIdentityMap()
+ public function testOrm()
+ {
+ $this->setUpRest('orm');
+ $this->_testActiveRecordApi();
+ }
+
+ public function testDbal()
+ {
+ $this->setUpRest('dbal');
+ $this->_testActiveRecordApi();
+ }
+
+ private function _testActiveRecordApi()
{
$user1 = new User();
$user1->setUsername('jwage');
@@ -64,6 +81,12 @@ public function testIdentityMap()
$this->assertEquals(3, $user3->getId());
+ $user3->setUsername('romanb_new');
+ $user3->save();
+
+ $user3test = User::find($user3->getId());
+ $this->assertEquals('romanb_new', $user3test->getUsername());
+
$test = User::findAll();
$this->assertEquals(3, count($test));
$this->assertTrue($user1 === $test[0]);
@@ -73,6 +96,7 @@ public function testIdentityMap()
$user3->delete();
$test = User::findAll();
+
$this->assertEquals(2, count($test));
}
}
@@ -80,21 +104,23 @@ public function testIdentityMap()
class TestFunctionalClient extends Client
{
public $name;
- public $ormEm;
+ public $source;
public $data = array();
public $count = 0;
- public function __construct($name, $ormEm)
+ public function __construct($name, $source)
{
$this->name = $name;
- $this->ormEm = $ormEm;
+ $this->source = $source;
}
public function execServer($request, $requestArray, $parameters = array(), $responseType = 'xml')
{
$requestArray = array_merge($requestArray, (array) $parameters);
- $server = new Server($this->ormEm, $requestArray);
- $server->addEntityAlias('Doctrine\Tests\REST\DoctrineUser', 'user');
+ $server = new Server($this->source, $requestArray);
+ if ($this->source instanceof EntityManager) {
+ $server->setEntityAlias('Doctrine\Tests\REST\DoctrineUser', 'user');
+ }
$response = $server->getRequestHandler()->execute();
$data = $request->getResponseTransformerImpl()->transform($response->getContent());
return $data;
@@ -193,7 +219,7 @@ public function setUsername($username)
/**
* @Entity
- * @Table(name="User")
+ * @Table(name="user")
*/
class DoctrineUser
{
View
2  tests/Doctrine/Tests/REST/TestInit.php
@@ -27,7 +27,7 @@ function autoload($className)
set_include_path(
__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'lib'
. PATH_SEPARATOR .
- '/Users/jwage/Sites/doctrine2/lib'
+ '/Users/jwage/Sites/doctrine2git/lib'
. PATH_SEPARATOR .
get_include_path()
);
Please sign in to comment.
Something went wrong with that request. Please try again.