Php 使用原则2将实体保存到RESTAPI而不是DB
这与我的另一个问题有关: 对于Symfony2中的项目,我需要能够使用远程(第三方)RESTful API持久化实体。我还希望能够从该API检索具有数据的实体 换句话说,我的对象保存在第三方数据库中。它们不保存在我自己的数据库中。每当我需要保存数据或查找数据时,我都使用他们的RESTAPI 有人指给我看了几个图书馆,包括。然而,没有一个能提供我想要的东西。Doctrine制作的是最好的选择,但是使用了活动记录模式,并没有提供所有Doctrine 2的内容。别误会,我已经使用活动记录实现很长一段时间了,但现在我爱上了条令的数据映射器模式 理想情况下,我希望能够使用Doctrine的ORM,并简单地用使用API调用保存实体的逻辑替换特定于数据库的部分。(当然,使用相同的API检索它们)。这样,我可以使用大致相同的语法保存实体:Php 使用原则2将实体保存到RESTAPI而不是DB,php,rest,symfony,doctrine-orm,persistence,Php,Rest,Symfony,Doctrine Orm,Persistence,这与我的另一个问题有关: 对于Symfony2中的项目,我需要能够使用远程(第三方)RESTful API持久化实体。我还希望能够从该API检索具有数据的实体 换句话说,我的对象保存在第三方数据库中。它们不保存在我自己的数据库中。每当我需要保存数据或查找数据时,我都使用他们的RESTAPI 有人指给我看了几个图书馆,包括。然而,没有一个能提供我想要的东西。Doctrine制作的是最好的选择,但是使用了活动记录模式,并没有提供所有Doctrine 2的内容。别误会,我已经使用活动记录实现很长一段时
// current way to save $entity in database:
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
// desired way to save $entity using REST API:
// (just an example, it doesn't have to be exactly like this)
$em = $this->getDoctrine()->getManager('rest');
$em->persist($entity);
$em->flush();
请注意,我并没有尝试构建自己的API,我只是尝试与第三方API通信以保存实体。我对学说还比较陌生,但到目前为止我还是喜欢它。我真的很喜欢将持久性逻辑与实体分开的想法,但到目前为止,我还不知道如何使用API来保存它们
Symfony的文档中有一篇文章描述了。我正在寻找一个类似的解决方案,但有一个实体管理器,使我能够使用REST而不是DB
我自己一直在尝试调整Doctrine的ORM,但我只重写了他们一半的代码,因为它(似乎)与特定于数据库的逻辑紧密耦合。当然,我可能在做一些愚蠢的事情
所以我的问题是,有没有办法用自定义的部分替换/覆盖条令ORM中特定于数据库的部分?没有重写所有持久化方法都应该通用的东西?以前做过吗?还是仅仅因为该原则旨在与数据库一起使用,而对于其他用途来说不够灵活,所以不可能实现
我自己的进步
CakePHP似乎能够做到这一点,因为它允许您定义一个自定义。通过这种方式,您可以使用SQL数据库保存模型,但也可以使用API、会话等。我想做大致相同的事情,但使用条令而不是CakePHP
更新1
实际的数据库查询似乎是由
. 还有其他几个xxxPersister类,用于处理不同类型的继承。可以用我们自己的类替换xxxPersister类,这样我们就可以用RESTAPI代码替换DB代码
持久化对象是在类的getEntityPersister()方法中创建的。类名是硬编码的,所以如果我们想使用自己的持久器,我们需要重写Doctrine\ORM\UnitOfWork
更新2
Doctrine\ORM\UnitOfWork
似乎是硬编码的,所以我们也需要覆盖它。但是,此类似乎包含一些特定于数据库的部分。例如,它的构造函数需要一个doctor\DBAL\Connection
对象作为参数。也许最好创建我们自己的EntityManger(实现Doctrine\Common\Persistence\ObjectManager
接口),只要不花费太多时间/精力
更新3
用于检索/加载/查找对象的特定于数据库的代码与用于持久化/删除等的代码位于同一类中:doctor\ORM\Persisters\xxxPersister
类。因此,如果我们能够用自己的对象替换它们,为了持久化对象,我们也可以检索对象。例如,当您调用$entityRepository->findAll()
时,它将返回$entityRepository->findBy(array())
(因为findAll()
只是findBy(array())
)的别名,它将运行以下代码:
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
return $persister->loadAll($criteria, $orderBy, $limit, $offset);
换句话说,一旦我们获得EntityManager
来创建正确的UnitOfWork
和xxxPersister
对象,我们就可以使用EntityRepository
中的find
方法
更新4
我发现为Doctrine开发了一个新特性:(另请参见)。这将使使用自定义持久器类更容易。我还不知道它是否能让我们创建一个非DB持久器,但它看起来很有希望。但是,上一次更新是在8月份,所以我不确定它是否仍在积极开发中。您可以使用它来构建一个REST客户端,它与目标服务器通信。这里的关键部分是从实体(本地)到RESTAPI(目标)的映射
简而言之:Doctrine2(本地数据库)->Rest客户端(实体到Rest映射)->请求(目标服务器)
条令/Rest还提供了另一种方法:条令Rest服务器,通过Rest(对服务器的请求)公开本地实体。但这不是你想要的。我认为你的方式不对。
我现在还没有准备好深入研究文档,但我认为原则堆栈是:
ORM->DQL(条令查询语言)->dbal->一些数据库sql
以及在DBAL中作为自定义数据库驱动程序的实现点
我认为创建公共REST驱动程序确实是一个有趣的特性,它可以轻松地与第三方服务集成 我不确定,但您可以尝试使用for实体通过REST执行持久化逻辑。由于没有现成的解决方案,我决定编写自己的解决方案。我叫它。它深受条令ORM的启发(事实上,它使用了条令Common提供的许多接口)
使用RAPL,我可以简单地编写一个小YAML文件来配置实体和web服务之间的映射,这样我就可以
/**
* This annotation marks the class as managed entity:
*
* @ORM\Entity
*
* You can either only use a resource name or the whole url of
* the resource to define your target. In the first case the target
* url will consist of the host, configured in your options and the
* given name. In the second one your argument is used as it is.
* Important: The resource name must begin with its protocol.
*
* @ORM\Table("products|http://www.yourSite.com/api/products")
*/
class Product {
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=100)
*/
private $name;
public function getId() {
return $this->id;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
}
<?php
namespace CircleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\HttpFoundation\Response;
class UserController extends Controller {
/**
* Sends the following request to the API:
* POST http://www.yourSite.com/api/products HTTP/1.1
* {"name": "Circle"}
*
* Let's assume the API responded with:
* HTTP/1.1 200 OK
* {"id": 1, "name": "Circle"}
*
* Response body is "1"
*/
public function createAction() {
$em = $this->getDoctrine()->getManager();
$entity = new CircleBundle\Entity\Product();
$entity->setName('Circle');
$em->persist($entity);
$em->flush();
return new Response($entity->getId());
}
/**
* Sends the following request to the API by default:
* GET http://www.yourSite.com/api/products/1 HTTP/1.1
*
* which might respond with:
* HTTP/1.1 200 OK
* {"id": 1, "name": "Circle"}
*
* Response body is "Circle"
*/
public function readAction($id = 1) {
$em = $this->getDoctrine()->getManager();
$entity = $em->find('CircleBundle\Entity\Product', $id);
return new Response($entity->getName());
}
/**
* Sends the following request to the API:
* GET http://www.yourSite.com/api/products HTTP/1.1
*
* Example response:
* HTTP/1.1 200 OK
* [{"id": 1, "name": "Circle"}]
*
* Response body is "Circle"
*/
public function readAllAction() {
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('CircleBundle\Entity\Product')->findAll();
return new Response($entities->first()->getName());
}
/**
* After sending a GET request (readAction) it sends the following
* request to the API by default:
* PUT http://www.yourSite.com/api/products/1 HTTP/1.1
* {"name": "myName"}
*
* Let's assume the API responded the GET request with:
* HTTP/1.1 200 OK
* {"id": 1, "name": "Circle"}
*
* and the PUT request with:
* HTTP/1.1 200 OK
* {"id": 1, "name": "myName"}
*
* Then the response body is "myName"
*/
public function updateAction($id = 1) {
$em = $this->getDoctrine()->getManager();
$entity = $em->find('CircleBundle\Entity\Product', $id);
$entity->setName('myName');
$em->flush();
return new Response($entity->getName());
}
/**
* After sending a GET request (readAction) it sends the following
* request to the API by default:
* DELETE http://www.yourSite.com/api/products/1 HTTP/1.1
*
* If the response is:
* HTTP/1.1 204 No Content
*
* the response body is ""
*/
public function deleteAction($id = 1) {
$em = $this->getDoctrine()->getManager();
$entity = $em->find('CircleBundle\Entity\Product', $id);
$em->remove($entity);
$em->flush();
return new Response();
}
}