承接 potfur/stash 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

potfur/stash

最新稳定版本:1.0.0-alpha

Composer 安装命令:

composer require potfur/stash

包简介

Stash: Mongo ODM

README 文档

README

Scrutinizer Code Quality Code Coverage Build Status License

Stash is an object-document mapper for MongoDB written in PHP. It adds a fully transparent persistence layer while still preserving MongoDB's ease of use and way of handling data.

This means that MongoDB can be used almost in the exact same way as it would be used with arrays. The small, but important, difference here is that instead of returning plain arrays, Stash will return objects (entities). And of course, Stash not only returns entities, but it also stores them.

Example

Model definitions:

$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)
        ]
    )
);

Database connection:

$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');

Entity creation and storage:

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);

And this is the stored MongoDB's semi-JSON representation. When saving objects (entities), Stash adds the _class field, where it stores the class name

{
  "_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
    }
  ]
}                                                     

Event subscription

Stash uses Symfonys Event Dispatcher for dispatching events.

  • find.after triggered after reading document from database and converting it to entity instance
  • persist.before is triggered before converting entity to array document
  • persist.after after document was saved (and updated with new _id if needed)
  • remove.before triggered before entity is removed from database

Each event is represented with Event entity, similar to Symfony's Event but with two methods getPayload and setPayload to manage subject entity.

$subscriber = new \Fake\EventSubscriber(
    [
        \Stash\Events::FIND_AFTER,
        \Stash\Events::PERSIST_BEFORE,
        \Stash\Events::PERSIST_AFTER,
        \Stash\Events::REMOVE_BEFORE
    ]
);
$eventDispatcher->addSubscriber($subscriber);

Configuring proxy

By default, all required proxy classes are generated at runtime. Generation uses a lot of reflection and it may cause poor performance. To prevent this, proxy generator needs to be configured to reuse generated proxies.

$config = new \ProxyManager\Configuration();
$config->setProxiesTargetDir(__DIR__ . '/generated/proxy/);
spl_autoload_register($config->getProxyAutoloader());

$proxyAdapter = new \Stash\ProxyAdapter($config);

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 6
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 6
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2015-06-10