neat/object 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

neat/object

Composer 安装命令:

composer require neat/object

包简介

Neat Object component

关键字:

README 文档

README

Stable Version Build Status codecov

Neat object component adds a simple yet intuitive ORM layer on top of the Neat database component.

Getting started

To install this package, simply issue composer on the command line:

composer require neat/object

Then initialize the object manager:

<?php

// Initialize the manager using a database connection and an object policy
$pdo        = new PDO('mysql:host=localhost;charset=utf8mb4;dbname=test', 'username', 'password');
$connection = new Neat\Database\Connection($pdo);
$policy     = new Neat\Object\Policy();
$manager    = new Neat\Object\Manager($connection, $policy);

// If you want easy access to static methods, set the Manager instance
Neat\Object\Manager::set($manager);

// Or set a factory that connects to the database only when needed
Neat\Object\Manager::setFactory(function () {
    $pdo        = new PDO('dsn', 'username', 'password');
    $connection = new Neat\Database\Connection($pdo);
    $policy     = new Neat\Object\Policy();

    return new Neat\Object\Manager($connection, $policy);
});

Creating an entity

Entities can be just plain old PHP objects

class User
{
    /** @var int */
    public $id;

    /** @var string */
    public $name;
}

To persist these entities into the database, we can use a repository:

$repository = Neat\Object\Manager::get()->repository(User::class);

$user = new User();
$user->name = 'John';

$repository->store($user);

echo $user->id; // 1

Find by identifier

If you know the identifier for your entity, you can access it using the has and get methods.

$repository = Neat\Object\Manager::get()->repository(User::class);

// Get the user at once
$user = $repository->get(1); // Returns user with id 1 or null if not found

// Or just check if it exists
if (!$repository->has(1)) {
    throw new Exception('boohoo');
}

To find and entity from a table using a composed primary key, you should pass the identifiers as an array.

Find using a query

The repository allows you to query for entities in many ways:

  • one returns one entity (or null if none matched the query)
  • all returns all entities matched by the query as an array
  • collection returns a collection instance containing the matched entities
  • iterate returns a generator allowing you to iterate over the matched entities
  • select returns a mutable query builder that allows chaining any of the methods above
  • sql returns a query object using a handwritten SQL query supplied as string

Each of these methods can be passed a query in several ways:

$repository = Neat\Object\Manager::get()->repository(User::class);

// Find one user with name John (note the [key => value] query array)
$user = $repository->one(['name' => 'John']);

// Find all users that have been deleted (the query is an SQL where clause)
$user = $repository->all('deleted = 1');

// Find all users using a complex query
$administrators = $repository
    ->select('u')
    ->innerJoin('user_group', 'ug', 'u.id = ug.user_id')
    ->innerJoin('group', 'g', 'g.id = ug.group_id')
    ->where('g.name = ?', 'administrators')
    ->orderBy('u.name')
    ->all();

// Get one user using your own SQL query
$user = $repository->sql('SELECT * FROM users WHERE id = ?', 1)->one();

// Or multiple in an array
$active = $repository->sql('SELECT * FROM users WHERE deleted = 0')->all();

Find using static access

To prevent littering your code with manager and repository instances, you can use the Storage trait to allow for static repository access:

class User
{
    use Neat\Object\Storage;

    /** @var int */
    public $id;

    /** @var string */
    public $name;
}

// The Storage trait gives you static access to repository methods
$user = User::get(1);
$users = User::all();
$latest = User::select()->orderBy('created_at DESC')->one();
foreach (User::iterate() as $user) {
    $user->greet();
}

Relations

If you need relations just use the Relations trait which supplies factory functions for hasOne/-Many and belongsToOne/-Many relations.

class User
{
    use Neat\Object\Storage;
    use Neat\Object\Relations;

    public function address(): Neat\Object\Relations\One
    {
        return $this->hasOne(Address::class);
    }
}

$user = User::one(...);

// Returns the address object for the user or null
$address = $user->address()->get();

// Relations are automatically stored when the parent model is stored:
$address = new Address();
$user->address()->set($address);
$user->store();
// Stores the user
// Sets the Address::$userId
// Stores the address

When you have multiple relations to the same class, make sure you assign each of them a unique role using the second parameter to avoid collisions between them:

class Appointment
{
    use Neat\Object\Storage;
    use Neat\Object\Relations;

    public function createdBy(): Neat\Object\Relations\One
    {
        return $this->belongsToOne(User::class, 'creator');
    }

    public function updatedBy(): Neat\Object\Relations\One
    {
        return $this->belongsToOne(User::class, 'updater');
    }
}

References

The column names and table names used for each relation have defaults that are determined by the Policy. When these defaults don't work, you can override them by passing a configuration closure as third parameter to the relation method of you choice:

class AgendaLine
{
    use Neat\Object\Storage;

    /** @var int */
    public $id;

    /** @var int */
    public $appointmentId;

    /** @var string */
    public $description;
}

class User
{
    use Neat\Object\Storage;

    /** @var int */
    public $id;

    /** @var int */
    public $alternativeId;
}

class Appointment
{
    use Neat\Object\Storage;
    use Neat\Object\Relations;

    /** @var int */
    public $id;

    /** @var int */
    public $createdBy;

    public function creator(): Neat\Object\Relations\One
    {
        // Pass reference configuration to belongsToOne as
        // callable(LocalKeyBuilder)
        return $this->belongsToOne(User::class, 'creator', function (Neat\Object\Relations\Reference\LocalKeyBuilder $builder) {
            // Use the local property name
            $builder->setLocalKey('createdBy');

            // Or alternatively, the local column name
            $builder->setLocalKeyColumn('created_by');

            // Set the remote property name
            $builder->setRemoteKey('alternativeId');

            // Or alternatively, the remote column name
            $builder->setRemoteKeyColumn('alternative_id');
        });
    }

    public function agendaLines(): Neat\Object\Relations\Many
    {
        // Pass reference configuration to hasOne and hasMany as
        // callable(RemoteKeyBuilder)
        return $this->hasMany(AgendaLine::class, 'agenda', function (Neat\Object\Relations\Reference\RemoteKeyBuilder $builder) {
            // The same local and remote key setters as with belongsToOne
            // can be used with hasMany and hasOne relations.
        });
    }

    public function attendees(): Neat\Object\Relations\Many
    {
        // Pass reference configuration to belongsToMany as
        // callable(JunctionTableBuilder)
        return $this->belongsToMany(User::class, 'attendees', function (Neat\Object\Relations\Reference\JunctionTableBuilder $builder) {
            // Set the junction table name and column names in addition to
            // the same local and remote key setters as with belongsToOne.
            $builder->setJunctionTable('appointment_attendee');
            $builder->setJunctionTableLocalKeyColumn('appointment_id');
            $builder->setJunctionTableRemoteKeyColumn('attendee_id');
            // Please note that the junction table doesn't have an entity
            // class. Therefore you cannot use class and property names.
        });
    }
}

Accessors

Accessor methods allow you to call methods like add, all, has, get, remove, select and set on your entity object directly:

class UserAccount
{
    use Neat\Object\Storage;
    use Neat\Object\Relations;

    // Use the Accessors trait to add accessor methods
    use Neat\Object\Accessors;

    public function address(): Neat\Object\Relations\One
    {
        return $this->belongsToOne(Address::class);
    }

    public function roles(): Neat\Object\Relations\Many
    {
        return $this->belongsToMany(Role::class);
    }
}

$user = UserAccount::one(...);

$user->getAddress(); // same as $user->address()->get();
$user->setAddress(...); // same as $user->address()->set(...);

$user->addRole(...); // same as $user->roles()->add(...);
$user->hasRole(...); // same as $user->roles()->has(...);
$user->deleteRole(...); // same as $user->roles()->delete(...);
$user->getRoles(); // same as $user->roles()->get();
$user->selectRoles(); // same as $user->roles()->select();

Translating $user->addRole() to $user->roles()->add() is done by the Policy. In its constructor you can provide a pluralize function to allow for proper translations:

// Use the Policy with custom $pluralize function to initialize your Manager
$policy = new Neat\Object\Policy(null, function (string $singular): string {
    return $singular . 's'; // lousy way of pluralizing relation names
});

Collections

Collections wrap an array of multiple items and offer a chainable way of accessing these items using several operations. Relations to multiple instances of a class (hasMany and belongsToMany) offer the same Collectible API:

class User
{
    use Neat\Object\Storage;
    use Neat\Object\Relations;

    public function roles(): Neat\Object\Relations\Many
    {
        return $this->belongsToMany(Role::class);
    }
}

$user = User::one(...);

// Both of these offer the Collectible API
$roles = Role::collection();
$roles = $user->roles();

// Get all roles, the first or the last role
$all = $user->roles()->all();
$first = $user->roles()->first();
$last = $user->roles()->last();

// Count roles
$count = $user->roles()->count();

// Get a filtered collection of roles
$filtered = $user->roles()->filter(function (Role $role) {
    return !$role->invisible;
});

// Get a sorted collection of roles
$sorted = $user->roles()->sort(function (Role $a, Role $b) {
    return $a->name <=> $b->name;
});

// Map roles and get the results in a collection
$names = $user->roles()->map(function (Role $role) {
    return $role->name;
});

// Or get the values of a single property in a collection
$names = $user->roles()->column('name');

// Chain multiple collection functions, then get an array of roles
$result = $user->roles()->filter(...)->sort(...)->all();

neat/object 适用场景与选型建议

neat/object 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 3.85k 次下载、GitHub Stars 达 4, 最近一次更新时间为 2018 年 05 月 04 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 neat/object 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

  • Stars: 4
  • Watchers: 2
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-05-04