定制 granadaorm/granada 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

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

granadaorm/granada

Composer 安装命令:

composer require granadaorm/granada

包简介

Active Record / ORM with eager loading, lazy loading and more

README 文档

README

Latest Stable Version Total Downloads Build Status

Granada is a easy to use Active Record implementation, and ORM based on Idiorm/Paris.

A quick view

use Granada\Model;

class User extends Model
{
    public function posts() {
        return $this->has_many('Post');
    }
}

class Post extends Model {}

// select
$user = User::where('name', 'John')->find_one();

// modify
$user->first_name = 'Doe';
$user->save();

// select relationship
$posts = $user->posts()->find_many();
foreach ($posts as $post) {
    echo $post->content;
}

You can read the Paris Docs on paris.readthedocs.org but be sure to read the additions below.

Install

Using composer:

composer require granadaorm/granada

Configure it:

require 'vendor/autoload.php';

use Granada\ORM;

ORM::configure('mysql:host=localhost;dbname=my_database');
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');

As always, you can check it in detail on Paris documentation

Additions

Eager loading

You can use the "with" method to add relationships eager loading to the query.

$results = User::with('avatar', 'posts')->find_many();

will use 3 querys to fetch the users and the relationships:

SELECT * FROM user
SELECT * FROM avatar WHERE user_id IN (....)
SELECT * FROM posts WHERE user_id IN (....)

It is possible to get the relationships results for each result, this way

foreach($results as $result){
    echo $result->avatar->img;
    foreach($result->posts as $post){
        echo $post->title;
    }
}

Lazy loading

Triying to access to a not fetched relationship will call and return it

$results = User::find_many();
foreach($results as $result){
    echo $result->avatar->img;
}

Notice that if there is no result for avatar on the above example it will throw a Notice: Trying to get property of non-object... Note: Maybe worth the effort to create a NULL object for this use case and others.

Eager loading with query control

Use with_{relation}() to eager-load a relationship and optionally configure the query via a callback:

// Basic — equivalent to with('manufactor')
$car = Car::with_manufactor()->find_one(1);

// Limit columns selected
$car = Car::with_manufactor(fn($q) => $q->select('id, name'))->find_one(1);
// SELECT `id`, `name` FROM `manufactor` WHERE ...

// Add ordering (has_many — multiple related records)
$manufactor = Manufactor::with_cars(fn($q) => $q->select('id, name')->order_by_desc('name'))->find_one(1);
// SELECT `id`, `name`, `manufactor_id` FROM `car` WHERE ... ORDER BY `name` DESC

Mix with the existing with() method:

$car = Car::with_manufactor(fn($q) => $q->select('name'))->with('owner')->find_one(1);

Nested eager loading via with_* inside the callback:

$owner = Owner::with_car(fn($q) => $q->select('id, manufactor_id')
    ->with_manufactor(fn($q) => $q->select('name'))
)->find_one(1);

Auto-included columns. You don't need to specify the columns the ORM uses for matching. They are added automatically:

Relationship type Column auto-added
belongs_to The related model's primary key
has_one, has_many The foreign key on the related table

If you already include these columns in your select(), they won't be added twice.

Column names. Use comma-separated strings for multiple columns: select('id, name'). Do not use select('id', 'name') — the second argument is an alias.

has_many_through. Qualify column names with the table because the query involves a join:

$car = Car::with_parts(fn($q) => $q->select('part.id, part.name'))->find_one(1);

Chained relationships with arguments for eager loading

It is possible to chain relationships and add arguments to the relationships calls

// chained relationships with dot notation
$results = User::with('posts.comments')->find_many();

// OR

// chained relationships use the "with" reserved word. (usefull if you want to pass arguments to the relationships)
$results = User::with(array('posts'=>array('with'=>array('comments'))))->find_many();

// SELECT * FROM user
// SELECT * FROM post WHERE user_id IN (....)
// SELECT * FROM comments WHERE post_id IN (....)

foreach($results as $result){
    foreach($posts as $post){
        echo $post->title;
        foreach($post->comments as $comment){
        echo $comment->subject;
        }
    }
}

// you can use arguments (one or more) to call the models relationships
$results = User::with(array('posts'=>array('arg1')))->find_many();
// will call the relationship defined in the user model with the argument "arg1"

Custom query filters

It's possible to create static functions on the model to work as filter in queries. Prepended it with "filter_":

use Granada\Model;

class ModelName extends Model {
    ....
    public static function filter_aname($query, $argument1, $argument2...){
        return $query->where('property', 'value')->limit('X')......;
    }
    ....
}

and call it on a static call

ModelName::aname($argument1, $argument2)->....

Multiple additions names for Granada

  • select_raw
  • group_by_raw
  • order_by_raw
  • raw_join
  • insert : To create and save multiple elements from an array
  • pluck : returns a single column from the result.
  • find_pairs : Return array of key=>value as result
  • save : accepts a boolean to use "ON DUPLICATE KEY UPDATE" (just for Mysql)
  • delete_many (accept join clauses)

Overload SET

// In the Model
protected function set_title($value)
{
    $this->alias = Str::slug($value);
    return $value;
}
// outside of the model
$content_instance->set('title', 'A title');

// works with multiple set too
$properties = array(
    'title'   => 'A title',
    'content' => 'Some content'
);
$content_instance->set($properties);

// try it with a direct assignement
$content_instance->title = 'A title';

Overload GET and MISSING property

// In the Model

// Work on defined
protected function get_path($value)
{
    return strtolower($value);
}

// and non-defined attributes.
protected function mising_testing()
{
    return 'whatever';
}
...

// outside of the model
echo $content_instance->path; // returns the lowercase path value of $content_instance
echo $content_instance->testing; // returns 'whatever' since we defined a missing_{attribute_name}

Of course, you still can define functions with the property name if you want to overload it completely.

Define resultSet (collection type) class on Model

Now is possible to define the resultSet class returned for a model instances result. (if return_result_sets config variable is set to true) Notice that the resultSet class defined must extends Granada\ResultSet and must be loaded

// In the Model
public static $resultSetClass = 'TreeResultSet';
// outside of the model
var_dump(Content::find_many());

// echoes
object(TreeResultSet)[10]
    protected '_results' => array(...)
....

ResultSets are defined by the model in the result, as you can see above. On eager load, the results are consistent. For example, if we have a Content model, with $resultSetClass = 'TreeResultSet' and a has_many relationship defined as media:

Content::with('media')->find_many();

will return a TreeResultSet with instances of Content each with a property $media containing Granada\ResultSet (the default resultSet if none if defined on the Model)

Basic Documentation comes from Paris

Paris

Feature complete

Paris is now considered to be feature complete as of version 1.4.0. Whilst it will continue to be maintained with bug fixes there will be no further new features added.

A lightweight Active Record implementation for PHP5.

Built on top of Idiorm.

Tested on PHP 5.2.0+ - may work on earlier versions with PDO and the correct database drivers.

Released under a BSD license.

Features

  • Extremely simple configuration.
  • Exposes the full power of Idiorm's fluent query API.
  • Supports associations.
  • Simple mechanism to encapsulate common queries in filter methods.
  • Built on top of PDO.
  • Uses prepared statements throughout to protect against SQL injection attacks.
  • Database agnostic. Currently supports SQLite, MySQL, Firebird and PostgreSQL. May support others, please give it a try!
  • Supports collections of models with method chaining to filter or apply actions to multiple results at once.
  • Multiple connections are supported

History

Granada was originally developed by Erik Wiesenthal, up to version 1.5. Further development started by Josh Marshall to release version 2.0

granadaorm/granada 适用场景与选型建议

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

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

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

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

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

  • Stars: 17
  • Watchers: 4
  • Forks: 3
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-2-Clause
  • 更新时间: 2018-10-02