定制 alcidesrh/laravel-generic-resource 二次开发

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

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

alcidesrh/laravel-generic-resource

Composer 安装命令:

composer require alcidesrh/laravel-generic-resource

包简介

A generic or agnostic Laravel's Resource and their CRUD (create, read, update, delete) operations.

README 文档

README

Basic use

  use Alcidesrh\Generic\GenericResource;

  $user = User::find(1);

  // It will only return the id and name fields.
  return new GenericResource( $user, ['id', 'name']);

This package can help you to return data as a traditional Laravel Resource without making a Resource or ResourceCollection for every single Model.


Table of Contents
  1. Requirements
  2. Installation
  3. Usage

Requirements

-Laravel >= 5
-php >= 7.0


Installation

composer require alcidesrh/laravel-generic-resource

Working with nested or related models

Supose the User class has a parent property of type User class as well, a belongsTo relation with itself. And also has a belongsToMany relation with Product class. So $user->parent returns an intance of User class and $user->products a collection of intances of Product class.

Let say we want a list of users with just these fields: id, name, parent (only the id and name fields of the parent) and products list (only the id, name and price fields of the product). This is how we can get only those data:

  use Alcidesrh\Generic\GenericResource;

  $user = User::find(1);
  return new GenericResource( $user, [
      'id',
      'name',
      'parent' => ['id', 'name'],
      'products' => ['id', 'name', 'price']
  ]);

You can add many nested level as the relations allow:

    ...
    'products' => [
      'id',
      'name',
      'price',
      'order' => [
        'id',
        'created_at',
        'company' => [
          'id',
          'name'
        ]
      ]
    ]

Important: In order to return nested relations data it is required make the query through the model's Facade.

    // this will work
    new GenericResource( User::find(1), ['id', 'name'] );

    // this will work
    new GenericResource( User::find(1), ['id', 'name', 'parent' => ['id', 'name']] );

    // this will work
    new GenericResource( DB::table('users')->where('id', 1)->first(), ['id', 'name'] )

    // this won't
    new GenericResource( DB::table('users')->where('id', 1)->first(), [
        'id',
        'name',
        'parent' => ['id', 'name']
        // it can not be access the parent property since the object retrieved is an stdClass type
    ] );

Note:

  • If the second argument (the array of fields to get) is not supplied, all fields of the model will be returned.
  • If one of the fields to return doesn't exist in the model, will be omitted in the result array.

GenericResourceCollection

   use Alcidesrh\Generic\GenericResourceCollection;

   $users = User::where('active', 1);
   // it will return a collection of user with only the id and name fields.
   return new GenericResourceCollection( $users->paginate( $perPage ), ['id', 'name']);

   //you can pass nested property as well as in the GenericResource
   return new GenericResourceCollection( $users->paginate( $perPage ), [
       'id',
       'name',
       'parent' => ['id', 'name'],
       'products' => ['id', 'name', 'price']
   ]);

Note: Both GenericResource and GenericResourceCollection classes were made following the guide line from the official Laravel's Api Resources documentation with some extra code to make it generic. So you can expect the same structure and behavior.


GenericController

The main goal of this package is to provide GenericResource and GenericResourceCollection. However this package also provides a GenericController which can be used to fetch data that doesn't require a complex query or transformation, and it will return a GenericResource or GenericResourceCollection only with the fields that were requested or all fields if none was requested.

It can help to prevent overloading the app with routes and controller functions for every small and simple data portion required dynamically in the front-end via ajax.

The GenericController has five routes:

Method: POST /generic/list
Method: POST /generic/create
Method: POST /generic/update
Method: POST /generic/item
Method: POST /generic/delete

/generic/list get a list. It return a GenericResourceCollection

axios.post("/generic/list", {
  // table to query
  table: "users",
  // page to return
  page: 1,
  // item per page
  itemsPerPage: 10,
  // fileds to return
  fields: ["id", "name", "created_at", "role_id", "email", "company_id"],
  // where clause: rule is column: value or column: {operator: someoperator, value: somevalue}
  // operator value should be some of these: '=', '!=', '<', '<=', '>', '>=', '<>', 'like', 'contain'
  where: {
    // will generate ( created_at > '2021-03-11 20:26:00.0' )
    created_at: { operator: ">", value: "2020-09-11 20:26:00.0" },
    // will generate ( email_verified_at IS NOT NULL )
    email_verified_at: { operator: "!=", value: null },
    // when the operator's parameter is omitted the default operator will be '=', will generate ( role_id = 2 )
    role_id: 2,
    // the non-existent 'contain' will generate ( email LIKE %legendary% AND email LIKE %zangetsu% )
    // this example zangetsu.ins@company.com and jhon.legendary.dc@company.com will match
    email: { operator: "contain", value: ["legendary", "zangetsu"] },
  },
  //orWhere clause accept same rules as simple where with one more
  orWhere: {
    // you can pass an array as a value, it will generate (role_id = 1 OR role_id = 2)
    role_id: [1, 2],
    // will generate (role_id != 1 OR role_id != 2)
    role_id: { operator: "!=", value: [1, 2] },
  },
  whereIn: {
    // return items with those ids
    id: [1, 23, 35],
  },
  whereNotIn: {
    // return items with neither of these ids
    id: [1, 23, 35],
  },
  whereBetween: {
    // return items with price between 25 and 35
    price: [25, 35],
  },
  // return items with price less than 25 and greater than 35
  whereNotBetween: {
    id: [25, 35],
  },
  // order by id ascendingly of course the value can be DESC
  orderBy: {
    id: "ASC",
  },
});

Note: It is not posible to ask for nested relations data in the fields parameter above due the generic nature of the query. DB Facade is used to make the query, which returns stdClass type.


/generic/create create an item. It will return a GenericResource

axios.post("/generic/create", {
  table: "roles",
  // fields to return in the GenericResource once created
  fields: ["id", "name"],
  // values: pair column: value
  values: {
    name: "Admin",
    slug: "admin",
  },
  // can insert many in one request
  many: [
    {
      name: "User editor",
      slug: "user-editor",
    },
    {
      name: "Forum admin",
      slug: "forum-admin",
    },
  ],
});

/generic/update update an item. It will return a GenericResource

axios
.post("/generic/update", {
  table: "roles",
  // id of the item to update
  id: 3,
  // many ids to update many items with the same values in one request.
  many: [35, 36, 37]
  // fields to return in the GenericResource once updated
  fields: ["id", "name"],
  // values: pair column: value
  values: {
    name: "Room Admin",
    slug: "room-admin",
  },
});

/generic/item to get an item. It will return a GenericResource

axios.post("/generic/delete", {
  table: "user",
  // id of the item to delete
  id: 3,
  //fields to return in the GenericResource
  fields: ["id", "name", "slug"],
});

/generic/delete delete an item

axios
.post("/generic/delete", {
  table: "user",
  // id of the item to delete
  id: 3,
});

Route namespace and pagination configuration

Once installed runing console command php artisan vendor:publish will publish the package's configuration. It can also be done manually copy /vendor/alcidesrh/generic-resource.php to /config

/config/generic-resource.php

return [

    /*
    |--------------------------------------------------------------------------
    | Laravel generic Resource package configuration
    |--------------------------------------------------------------------------
    |
     */
    // configure route and prefix
    // e.g. to have this route https://yourdomain/products/items for items list
    // change 'prefix' key value to 'products' and 'list_route_name' key value to 'items'
    'route' => [

        //Route's prefix for generic CRUD(create, read, update and delete) operations
        //Deafault 'generic' e.g.: axios.post( 'https://yourdomain/generic' )
        'prefix' => 'generic',

        //Route for list of generic items.
        //Deafault 'list' e.g. axios.post( 'https://yourdomain/generic/list' )
        'list_route_name' => 'list',

        //Route to create an item.
        //Deafault 'create' e.g. axios.post( 'https://yourdomain/generic/create', {table: 'users', values: [ {username: 'whatever', role_id: 1}], field: [id, username] } )
        'create_route_name' => 'create',

        //Route to update an item.
        //Deafault 'update'  e.g. axios.post( 'https://yourdomain/generic/update', {table: 'users', id: 1, values: [ {username: 'whatever', role_id: 1}], field: [id, username] } )
        'update_route_name' => 'update',

        //Route to get an item.
        //Deafault 'item' e.g. axios.post( 'https://yourdomain/generic/item', {table: 'users', fields: [ {username: 'whatever', role_id: 1}] } )
        'show_route_name' => 'item',

        //Route to delete a generic item.
        //Deafault 'delete' e.g. axios.post( 'https://yourdomain/generic/delete', {table: 'users', id: 1} )
        'delete_route_name' => 'delete',
    ],
    // configure pagination items per page and parameters names.
    'pagination' => [

        //Items per page. Default 20.
        'itemsPerPage' => 20,

        //Name of the param of the current page e.g. axios.post( 'https://yourdomain/generic/delete', {table: 'users', page: 1} )
        'name_param_page' => 'page',

        //Name of the param of the number of items per page e.g. axios.post( 'https://yourdomain/generic/list', {table: 'users', page: 1, itemsPerPage: 30} )
        'name_param_item_per_page' => 'itemsPerPage',
    ],
];

If you find this package useful please consider star it. Thank you.

License

This Generic Resource package for Laravel is open-sourced software licensed under the MIT license

alcidesrh/laravel-generic-resource 适用场景与选型建议

alcidesrh/laravel-generic-resource 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 29 次下载、GitHub Stars 达 3, 最近一次更新时间为 2021 年 03 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

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

围绕 alcidesrh/laravel-generic-resource 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-03-29