potfur / stash
Stash: Mongo ODM
1.0.0-alpha
2015-08-23 11:43 UTC
Requires
- php: >=5.5.9|~7.0
- ext-mongo: *
- ocramius/proxy-manager: 1.0.*
- symfony/event-dispatcher: ^2.7
Requires (Dev)
- phpmd/phpmd: ~2.2
- phpunit/phpunit: ~4.6
- squizlabs/php_codesniffer: ~2.3
This package is not auto-updated.
Last update: 2024-09-14 17:32:03 UTC
README
Stash 是一个用 PHP 编写的 MongoDB 对象-文档映射器。它在保留 MongoDB 易用性和数据处理方式的同时,添加了一个完全透明的持久化层。
这意味着 MongoDB 可以几乎以完全相同的方式使用,就像使用数组一样。这里的细微但重要的区别是,而不是返回普通数组,Stash 将返回对象(实体)。当然,Stash 不仅返回实体,还存储它们。
示例
模型定义
$models = new \Stash\ModelCollection(); $models->register( new \Stash\Model\Model( '\Order', [ new \Stash\Converter\Type\Id(), new \Stash\Converter\Type\Document('customer'), new \Stash\Converter\Type\ArrayOf('items', Fields::TYPE_DOCUMENT) ] ), 'order' ); $models->register( new \Stash\Model\ '\OrderItem', [ new \Stash\Converter\Type\Scalar('name', Fields::TYPE_STRING), new \Stash\Converter\Type\Scalar('amount', Fields::TYPE_INTEGER), new \Stash\Converter\Type\Scalar('cost', Fields::TYPE_INTEGER) ] ) ); $models->register( new \Stash\Model\ '\Voucher', [ new \Stash\Converter\Type\Scalar('name', Fields::TYPE_STRING), new \Stash\Converter\Type\Scalar('cost', Fields::TYPE_INTEGER) ] ) ); $models->register( new \Stash\Model\ '\Customer', [ new \Stash\Converter\Type\Scalar('name', Fields::TYPE_STRING), new \Stash\Converter\Type\Document('address') ] ) ); $models->register( new \Stash\Model\ '\CustomerAddress', [ new \Stash\Converter\Type\Scalar('address', Fields::TYPE_STRING), new \Stash\Converter\Type\Scalar('city', Fields::TYPE_STRING), new \Stash\Converter\Type\Scalar('zip', Fields::TYPE_STRING) ] ) );
数据库连接
$types = [ new \Stash\Converter\Type\IdType(), new \Stash\Converter\Type\BooleanType(), new \Stash\Converter\Type\IntegerType(), new \Stash\Converter\Type\DecimalType(), new \Stash\Converter\Type\StringType(), new \Stash\Converter\Type\DateType(), new \Stash\Converter\Type\ArrayType(), new \Stash\Converter\Type\DocumentType() ]; $proxyAdapter = new \Stash\ProxyAdapter(new \ProxyManager\Factory\LazyLoadingValueHolderFactory()); $converter = new \Stash\Converter\Converter($types); $referencer = new \Stash\ReferenceResolver($models); $documentConverter = new \Stash\DocumentConverter($converter, $referencer, $models, $proxyAdapter); $eventDispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher(); $connection = new \Stash\Connection(new \MongoClient(), $documentConverter, $eventDispatcher); $connection->selectDB('test');
实体创建和存储
class Order { private $id; private $customer; private $items; public function __construct($customer, $items) { $this->customer = $customer; $this->items = $items; } } class OrderItem { private $name; private $amount; private $cost; public function __construct($name, $amount, $cost) { $this->name = $name; $this->amount = $amount; $this->cost = $cost; } } class Voucher { private $name; private $discount; public function __construct($name, $discount) { $this->name = $name; $this->discount = $discount; } } class Customer { private $name; private $address; public function __construct($name, CustomerAddress $address) { $this->$name = $name; $this->address = $address; } } class CustomerAddress { private $address; private $city; private $zip; public function __construct($address, $city, $zip) { $this->address = $address; $this->city = $city; $this->zip = $zip; } } $order = new Order( new Customer('Joe Doe', new CustomerAddress('Mongo alley', 'Somewhere', '12345')), [ new OrderItem('Foos', 10, 1000), new Voucher('Voucher', 250) ] ); $connection->getCollection('order')->save($order);
这是存储的 MongoDB 的半 JSON 表示形式。在保存对象(实体)时,Stash 添加 _class
字段,其中存储类名
{
"_id" : ObjectId("55746f4f87dee7bc0b000033"),
"_class" : "Order",
"customer" : {
"_class" : "Customer",
"address" : {
"_class" : "CustomerAddress",
"address" : "Mongo alley",
"city" : "Somewhere",
"zip" : "12345"
}
},
"items" : [
{
"_class" : "OrderItem",
"name" : "Foos",
"amount" : 10,
"cost" : 1000
},
{
"_class" : "Voucher",
"name" : "Voucher",
"discount" : 250
}
]
}
事件订阅
Stash 使用 Symfonys Event Dispatcher 来派发事件。
find.after
在从数据库读取文档并将其转换为实体实例后触发persist.before
在将实体转换为数组文档之前触发persist.after
在文档保存后(如果需要,更新新_id
)remove.before
在实体从数据库中删除之前触发
每个事件都由 Event
实体表示,类似于 Symfony 的 Event
,但有两个方法 getPayload
和 setPayload
来管理主题实体。
$subscriber = new \Fake\EventSubscriber( [ \Stash\Events::FIND_AFTER, \Stash\Events::PERSIST_BEFORE, \Stash\Events::PERSIST_AFTER, \Stash\Events::REMOVE_BEFORE ] ); $eventDispatcher->addSubscriber($subscriber);
配置代理
默认情况下,所有必需的代理类在运行时生成。生成使用大量的反射,可能会导致性能较差。为了防止这种情况,代理生成器需要配置为重用生成的代理。
$config = new \ProxyManager\Configuration(); $config->setProxiesTargetDir(__DIR__ . '/generated/proxy/); spl_autoload_register($config->getProxyAutoloader()); $proxyAdapter = new \Stash\ProxyAdapter($config);