承接 vladshut/dbal-gateway 相关项目开发

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

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

vladshut/dbal-gateway

Composer 安装命令:

composer require vladshut/dbal-gateway

包简介

Table Gateway for Doctrine DBAL

README 文档

README

Build Status

Doctrine DBAL is a fantastic extension to PDO but writing CRUD code for simple 1 to 1 mappings still represents a time sink. This component implements Table Gateway on top of Doctrine DBAL and is heavily inspired by zf2 Table Gateway.

What are the benefits?

  1. Using metadata the gateway will convert values, for example DateTime is converted to a stamps and the stamp is converted back to DateTime.
  2. Events system, e.g pre_select , post_delete , pre_insert... based around the symfony2 event dispatcher.
  3. Query Logger using Monolog, you would normally write this yourself.
  4. Builder can map records to entities, you could build an active record on top of this gateway.
  5. Supply a collection class and it will load them into it.
  6. Fluid interface for running selects, inserts, updates and deletes.
  7. Faster than manual CRUD.

Whats are the cons?

  1. Loose auto-completion in your IDE, for subclasses, only get it for the bases classes.
  2. Overhead a little more memory and extra method calls.

Install

This component can be installed via composer.

{
    "require" : {
        "icomefromthenet/dbal-gateway" : "dev-master",
    }

}

Usage.

There are 3 components to every table.

  1. Metadata instanceof DBALGateway\Metadata\Table.
  2. Subclass of DBALGateway\Table\AbstractTable the gateway.
  3. Subclass of DBALGateway\Query\AbstractQuery the query class.

There are 2 optional components to every table

  1. Custom result-set implementation of Doctrine\Common\Collections\Collection.
  2. Entity builder implementation of DBALGateway\Builder\BuilderInterface.

1. The Metadata

Assume have the following databse table.

delimiter $$

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `first_name` varchar(45) COLLATE utf8_unicode_ci NOT NULL,
  `last_name` varchar(45) COLLATE utf8_unicode_ci NOT NULL,
  `dte_created` datetime NOT NULL,
  `dte_updated` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci$$

You can declare the metadata as follows.

<?php
namespace ExampleFile

use DBALGateway\Metadata\Table;

call_user_func(function(){

    # create the table object
    $table = new Table('users');
    
    # assign normal columns 
    $table->addColumn('id',"integer", array("unsigned" => true));
    $table->addColumn('username', "string", array("length" => 32));
    $table->addColumn('first_name', "string", array("length" => 45));
    $table->addColumn('last_name',"string", array("length" => 45));
    $table->addColumn('dte_created','datetime');
    $table->addColumn('dte_updated','datetime');
    $table->setPrimaryKey(array("id"));

    # assign virtual columns, these are perfect for calulated values.
    # these columns can not be inserted but will be converted if found in a result-set.
    $table->addVirtualColumn('uptime',"datetime");
    
    return $table;    
});

The datatypes (second argument in addColumn) are not mysql types but doctrine types, the mapping can be found under Doctrine\DBAL\Platforms\{MYPLATFORM}.

2. The Table Gateway.

You will need to declare a subclass of DBALGateway\Metadata\Table and override the method newQueryObject().

<?php
namespace DBALGateway\Tests\Base\Mock;

use DBALGateway\Table\AbstractTable;

class MockUserTableGateway extends AbstractTable
{
    /**
      *  Create a new instance of the querybuilder
      *
      *  @access public
      *  @return QueryBuilder
      */
    public function newQueryBuilder()
    {
        return new MockUserQuery($this->adapter,$this);
    }

}

You may also include other custom code on this class. But note all methods a marked as protected be careful with naming.

3. The QueryClass

You will need to subclass DBALGateway\Query\AbstractQuery which is itself a subclass of Doctrine\DBAL\Query\QueryBuilder.

<?php
namespace DBALGateway\Tests\Base\Mock;

use DBALGateway\Query\AbstractQuery;
use DateTime;

class MockUserQuery extends AbstractQuery
{
    
    public function filterByUser($id)
    {
        $this->where('id = :id')->setParameter('id', $id, $this->getGateway()->getMetaData()->getColumn('id')->getType());
        return $this;
    }
    
    public function filterByUsername($name)
    {
        $this->where('username = :username')->setParameter('username', $id, $this->getGateway()->getMetaData()->getColumn('username')->getType());
        
        return $this;
    }
    
    
    public function filterByDateCreated(DateTime $created)
    {
        $this->where('dte_created = :dte_created')->setParameter('dte_created', $id, $this->getGateway()->getMetaData()->getColumn('dte_created')->getType());
        
        return $this;
    }
    
    public function filterByDateUpdated(DateTime $updated)
    {
        $this->where('dte_updated = :dte_updated')->setParameter('dte_updated', $id, $this->getGateway()->getMetaData()->getColumn('dte_updated')->getType());
        
        return $this;
    }
    
}

Each custom filter should do the following.

  1. Set a unique named parameter.
  2. Set the parameter value and fetch the doctrine type from the meta-data in the table gateway.
  3. Return $this.

4. The Collections class.

When using find() on the gateway results will be stored in a collection class offerd by doctrine Doctrine\Common\Collections\ArrayCollection. If the gateway's constructor is passed an instance an alternative that inherits the interface from Doctrine\Common\Collections\Collection it will clone a copy and use that.

use Doctrine\Common\Collections\Collection;


class CustomCollection implements Collection
{
 .....

}

$collection = new CustomCollection();

$gateway = new MockUserGateway('user',$conn,$event,$meta,$collection,null);

This gateway will clone $collection on each call to find. Note: findOne() does not return collection just entity/array.

5. The Entity Builder

When using find() or findOne() each result found in the set will be passed to the builder for conversion into an entity. A builder must implement the interface found at DBALGateway\Builder\BuilderInterface.

use DBALGateway\Builder\BuilderInterface;

class EntityBuilder implements BuilderInterface
{
     /**
      *  Convert data array into entity
      *
      *  @return mixed
      *  @param array $data
      *  @access public
      */
    public function build($data)
    {
        $user = new UserEntity();
        
        $user->id = $data['id'];
        $user->username = $data['username'];
        
        ... etc
        
        return $user;
        
    }
    
    /**
      *  Convert and entity into a data array
      *
      *  @return array
      *  @access public
      */
    public function demolish($entity)
    {
    
    }

}

$builder = new EntityBuilder();
$gateway = new MockUserGateway('users',$conn,$event,$meta,null,$builder);

Note: If a collection class is used this new entity will be given to the collection.

Running Queries

Run an INSERT Query.

$gateway = new MockUserGateway('users',$conn,$event,$meta);

$success = $gateway->insertQuery()
             ->start()
                ->addColumn('username','ausername')
                ->addColumn('first_name','myfname')
                ->addColumn('last_name','mylname')
                ->addColumn('dte_created',new DateTime())
                ->addColumn('dte_updated',DateTime())
             ->end()
           ->insert(); 

if($success) {
 
 $id = $gateway->lastInsertId();
 
}

Run an UPDATE Query.

$gateway = new MockUserGateway('users',$conn,$event,$meta);

$success = $gateway->updateQuery()
             ->start()
                ->addColumn('username','ausername')
                ->addColumn('first_name','myfname')
                ->addColumn('last_name','mylname')
                ->addColumn('dte_created',new DateTime())
                ->addColumn('dte_updated',DateTime())
             ->where()
                ->filterByUser(101)
             ->end()
           ->update(); 

if($success) {
 
 echo 'table row was updated';
 
}

Run a DELETE Query.

$gateway = new MockUserGateway('users',$conn,$event,$meta);

$success = $gateway->deleteQuery()
             ->start()
                ->filterByUser(1)
             ->end()
           ->delete(); 

if($success) {
 
 echo 'table row was removed';
 
}

Run a SELECT Query.

There are two methods findOne() and find().

$gateway = new MockUserGateway('users',$conn,$event,$meta);

$result = $gateway->selectQuery()
             ->start()
                ->filterByUser(1)
             ->end()
           ->findOne(); 

if($result !== null) {
    echo $result['id'];
    echo $result['username'];
    echo $result['dte_created']->format('U');
}
$gateway = new MockUserGateway('users',$conn,$event,$meta);

$result = $gateway->selectQuery()
             ->start()
                ->filterByUser(1)
             ->end()
           ->find(); 

if($result !== null) {
    echo $result[0]['id'];
    echo $result[0]['username'];
    echo $result[0]['dte_created']->format('U');
}

Instance a Gateway?

A Gateway has the following dependecies.

  1. The table name in the schema.
  2. The Doctrine\DBAL\Connection $connection.
  3. An instance of Symfony\Component\EventDispatcher\EventDispatcherInterface.
  4. The meta data for table instance of DBALGateway\Metadata\Table.
  5. (optional) a result-set to clone an instance class that implements Doctrine\Common\Collections\Collection
  6. (optional) a enity builder an instance class that implements DBALGateway\Builder\BuilderInterface
 new MockUserGateway('users',$conn,$event,$meta,$result_set,$builder);

Features and Events.

The Gateway emits a number of events.

Event Name Event Description
pre_initilize Occurs during object construction.
post_initilize Occurs after object construction.
pre_select Occurs before a select query is run.
post_select Occurs after a select query is run.
pre_delete Occurs before delete query is run.
post_delete Occurs after delete query is run.
pre_insert Occurs before an insert is run.
post_insert Occurs after an insert is run.
pre_update Occurs before an update is run.
post_update Occurs after an update is run.

For an example see the BufferedQueryLogger.

vladshut/dbal-gateway 适用场景与选型建议

vladshut/dbal-gateway 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 13 次下载、GitHub Stars 达 0, 最近一次更新时间为 2018 年 11 月 23 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「database」 「gateway」 「doctine」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 vladshut/dbal-gateway 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 vladshut/dbal-gateway 我们能提供哪些服务?
定制开发 / 二次开发

基于 vladshut/dbal-gateway 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-11-23