unique/yii2-vue

简化在 Yii2 框架中使用 Vue。

dev-main 2024-03-15 21:45 UTC

This package is auto-updated.

Last update: 2024-09-15 22:48:45 UTC


README

此包为 Yii2 框架上的 Vuejs v3 提供了一个非常基本的模型管理系统。此外,允许您通过 yii2 AssetBundle 容易地控制您的 Vue 应用资产。

安装

此组件需要 php >= 8.0。要安装它,请将以下内容添加到您的 composer.json 中

    "require": {
        ...
        "unique/yii2-vue": "@dev"
    },

目前,此包依赖于 JQuery 进行 AJAX 调用和其他操作。可能将来会将其解耦...

用法

要使用此包,您需要创建自己的 AssetBundle 文件并在其中定义您的 VUE 应用程序。您可以使用包含的 \unique\yii2vue\assets\VueAssetBundle,以帮助进行一些资产加载,例如

    class VueAppAssets extends VueAssetBundle {

        public $sourcePath = __DIR__ . '/vue-app';

        public $jsOptions = [
            'position' => View::POS_HEAD
        ];

        public $depends = [
            Yii2VueComponentsAssets::class
        ];

        public function init() {

            parent::init();
            $this->loadPath( __DIR__ . DIRECTORY_SEPARATOR . 'vue-app' . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . 'models' );
        }
    }

VueAssetBundle 提供了一种轻松添加给定路径中所有 js 和 css 文件的方式。这对于加载所有模型很有用。如果您只想添加特定的模型、组件或应用程序,可以使用相应的 addModel()addComponents()addApplication() 方法。

例如,在您的视图文件中,您可以注册您创建的包并添加一个特定的应用程序

    ( \app\assets\VueAppAssets::register( $this ) )
        ->addApplication( 'accounts-index' )
        ->addComponent( 'bootstrap-input' );

您可以通过覆盖相应的 VueAssetBundle 属性来自定义查找每个文件的位置。例如

    class VueAppAssets extends VueAssetBundle {

        public string $sourcePath = __DIR__ . DIRECTORY_SEPARATOR . 'myassets';

        public string $applications_path = 'myjs/apps/';
        public string $mixins_path = 'myjs/mixins/';
        public string $components_path = 'myjs/components/';
        public string $models_path = 'myjs/models/';
    }

路径是相对于资产文件所在的位置的。在这个特定的例子中,当调用 ( \app\assets\VueAppAssets::register( $this ) )->addApplication( 'accounts-index' ) 时,这会转换为生成一个 script 标签

    <script type="/assets/.../myjs/apps/accounts-index.js"

如果您依赖于提供的 Yii2VueComponentsAssets 类,这将提供一个类似于原生 Yii2 模型系统的非常基本的模型管理系统。

默认情况下,它还会加载 VueAssets 包,该包加载 vuejs。如果您想使用自己的 vuejs,您可以在 config/params.php 文件中禁用此行为

    return [
        'use_vue_dependancy' => false,
        ...
    ];

模型和模型管理器的使用

一个基本的模型文件可能看起来像这样

/**
 * @property {int} id
 * @property {string} name
 * ... other attribute definition
 * 
 * @property {Type} type
 * ... other relations definition
 */
class MyModel extends Model {

    /**
     * The data to be passed to the API to create or update the model. (like a serialization of the Model)
     * @returns {Object}
     */
    toBody() {

        return {
            id: this.id,
            name: this.name,
            // ... other properties
        }
    }

    /**
     * Model Relationship definition.
     * @returns {Relation[]}
     */
    relations() {
        return {
            type: new Relation( Relation.TYPE_HAS_ONE, Type ),
        }
    }

    /**
     * Sets the primary keys to the object, to be used when updating the model.
     * @param {Object} data
     * @returns {Object}
     */
    setPrimaryKeys( data ) {
        data['id'] = this.id;
        return data;
    }
}

要创建此模型,您可以使用提供的构造函数

    let my_model = new MyModel( { id: 1, name: 'ABC', 'type': { type_name: 'Name', ... } } );

这传播了所有给定的属性并创建了所有关系。它专门设计用于与 Yii2 序列化模型一起使用。

要控制多个模型,您可以使用提供的 ModelsManager(或通过扩展它来创建一个新的 ModelsManager)

    let my_models_manager = new ModelsManager( {
        access_token: '(string) An access token, that, if provided, will be sent with API requests' + 
            'as a basic Auth header. The string will be sent as a username.',
    
        url_create: '(string) A URL that will be used to create new Models',
        url_update: '(string) A URL that will be used to update Models',
        url_delete: '(string) A URL that will be used to delete Models',
        url_list: '(string) A URL that will be used to reload data',

        endpoint_model_class: '(string) A php class name of the model used in the backend. (can be' +
            'used to update many managers data at once)',
        model_class: '(string) A JS model\'s class name, that will be created by this Manager',
        model_id: '(string, default="id") a property, which will be used to index models by'
    } );

    my_models_manager.setData( 
        serialized_php_models,  // serialized data, which to use to create the models
        false   // (bool) Are we setting models that are new (not in DB yet)?
    )

ModelsManager 方法

  • reloadData() 用来在管理器中重新加载数据。必须指定 url_list。

  • updateData( new_data: Object, delete_missing: boolean = true ) 这将迭代此管理器管理的所有模型,并将它们的属性更新以反映给定的新数据。如果需要创建模型,它们将被创建。但是,只有当 delete_missing === true 时,对象才会从存储中删除 new_data 和它的关系必须使用与 ModelsManager.data 中相同的键进行索引。

  • setData( models: Array, new_records: bool ) 从管理器中擦除旧数据并设置新数据,通过创建新模型。new_records 参数用于设置模型是否需要创建(当为 true 时),或更新(当为 false 时)。

  • addItem( item: Model, new_record: bool ) 将模型添加到数据存储(不调用 API)。new_records 参数用于设置模型是否需要创建(当为 true 时),或更新(当为 false 时)。

  • static handleUnsuccessfulRequest( model: Model, data: Object, default_key: string ) 根据响应的 data 在 Model 的 errors 字段上设置字段错误。 data - 具有以下结构

{
    success: boolean, // was an operation successful. If it's given here, then usually this should be set to false.,
    data: object, // either a serialized Yii2 Exception, or a serialized Model with validation errors.
}

data.data 是序列化的 Yii2 异常时,它将具有以下字段

{
    name: string,   // Exception class name,
    message: string,    // Exception message
}

错误将被设置到模型提供的 default_key 属性。

data.data 是序列化的具有验证错误的 Yii2 Model 时,它将具有以下结构

[
    { 
        field: string,      // Field name that violated a validation rule,
        message: string,    // Validation message
    },
    ...
]

通过在 field 中提供完整路径,也可以为 Model 的关系设置错误。例如,如果模型 Brand 有一个名为 cars 的 HAS_MANY 关系和 Car 类,以及一个与 Manufacturer 类的 HAS_ONE 关系 manufacturer,在向 API 发起失败的请求后,我们可能收到以下响应

{
    success: false,
    data: [
        { field: "name", message: "Bad name" },          // This is an error for Brand.name property
        { field: "cars.3.engine", message: "..." },      // This is an error for Brand.cars[3].engine property and will accordingly be set on a Car class
        { field: "manufacturer.year", message: "..." }   // This is an error for Brand.manufacturer.year property and will be set on a Manufacturer class
    ]
}

请注意,Yii2 本身没有原生的关系保存能力,因此,您需要自己实现后端逻辑。

  • deleteItem( item_id: string|int, remove_from_data: bool ) 调用 API 来移除给定的 ID。如果 remove_from_data 为 true,则成功调用后,数据也会从 Manager 中删除。

  • saveItem( item: Model, request_data: Object ) 调用 API 来创建或更新给定的模型。可以通过提供 request_data 对象来传递额外的数据。它将与要保存的 Model 的数据合并。(Model 的数据优先)。

ModelsManagerRegister

所有创建的 ModelsManager 实例都自动注册到 ModelsManagerRegister 的静态实例。可以使用 ModelsManagerRegister 同时更新多个 ModelsManger。当您进行的 API 调用不仅更新给定的模型,还更新其他模型时,这很方便。

在这种情况下,API 调用可以返回 _list_changes_ 来更新其他模型。例如,假设我们正在创建一个新的 Car 模型,该模型更新 Stats 模型以反映相同 make_id 的汽车数量。那么我们的 API 可能会返回如下数据

    {
        ...,
        "_list_changes_": {
            "\\app\\models\\Car": {
                "1067": {
                    "id": 1067,
                    "make_id": 3,
                    ...
                }
            },
            "\\app\\models\\Stat": {
                "3": {
                    "count": 52
                }
            }
        }
    }

现在我们可以调用 ModelsManagerRegister.updateListChanges( data ),这将在我们创建了 CarStat 模型的 ModelsManager 的情况下更新它们中的数据。

使用 Yii2 命令创建 JS 模型文件

您可以通过调用以下内容轻松创建一个 JS 模型

    yii vue-assets/generate-model [PHP_CLASS_NAME]

如果您跳过了 [PHP_CLASS_NAME],则在命令运行时您需要指定它。这应该是一个完全命名空间化的类名。

您还应该在您的 config/console.php 文件中指定生成的模型的位置

    'controllerMap' => [
        'vue-assets' => [
            'class' => \unique\yii2vue\commands\VueAssetsController::class,
            'vue_asset_models_path' => ... // path to directory where to put generated JS models,
        ]
    ],