mcpField
P
product-type-development

product-type-development

github.com/bagisto开发13221 次安装2 周前更新
代码仓库

关于 product-type-development

面向 Bagisto 开发者的产品类型开发指南,介绍如何注册自定义类型并扩展其行为。指南涵盖可售性、库存、定价、验证、管理界面和购物车处理。

主要功能

  1. 01配置并注册自定义产品类型
  2. 02通过 AbstractType 扩展产品行为
  3. 03设置可售性与库存规则
  4. 04定义定价和类型专属验证
  5. 05自定义管理界面和购物车数据

适用场景

  1. 01在 Bagisto 中实现订阅产品
  2. 02为服务类产品添加专属定价与验证
  3. 03调整自定义产品的库存和购物车逻辑

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bagisto/agent-skills --skill product-type-development

安装后在 Claude Code 中输入/product-type-development确认已加载。

详细介绍

Bagisto 中的产品类型开发

概述

在 Bagisto 中创建自定义产品类型,可以定义符合业务需求的专用产品行为。无论您需要订阅产品、租赁商品、数字服务还是复杂的产品变体,自定义产品类型都能灵活满足您的商店需求。

适用场景

在以下情况下启用此技能:

  • 在 Bagisto 中创建新的产品类型
  • 构建订阅或服务类产品
  • 实现自定义产品行为
  • 添加特定类型的验证和定价
  • 修改库存处理方式

@config:产品类型配置

基本配置结构

Config/product-types.php 文件是一个简单的 PHP 数组,用于注册您的产品类型:

<?php

return [
    'subscription' => [
        'key'   => 'subscription',
        'name'  => 'Subscription',
        'class' => 'Webkul\SubscriptionProduct\Type\Subscription',
        'sort'  => 5,
    ],
];

必需的配置属性

属性描述示例
key唯一标识符(与数组键一致)'subscription'
name管理后台下拉菜单中显示的名称'Subscription'
class产品类型类的完整命名空间'Webkul\SubscriptionProduct\Type\Subscription'
sort下拉菜单中的排序位置(可选,默认为 0)5

Bagisto 如何使用此配置

1. 创建管理后台产品
  • 从配置中读取所有已注册的产品类型
  • 在“产品类型”下拉菜单中显示这些类型
  • 使用 name 显示名称,并使用 sort 排序
2. 实例化产品类型
  • 使用 key 查找产品的类型
  • 创建 class 的实例
  • 调用该实例上的方法以处理产品行为
3. 加载配置

您的服务提供程序会合并配置:

public function register(): void
{
    $this->mergeConfigFrom(
        dirname(__DIR__) . '/Config/product-types.php',
        'product_types'
    );
}

多种产品类型

<?php

return [
    'subscription' => [
        'key'   => 'subscription',
        'name'  => 'Subscription',
        'class' => 'Webkul\SubscriptionProduct\Type\Subscription',
        'sort'  => 5,
    ],
    
    'rental' => [
        'key'   => 'rental',
        'name'  => 'Rental Product',
        'class' => 'Webkul\RentalProduct\Type\Rental',
        'sort'  => 6,
    ],
];

@abstract:AbstractType 方法

AbstractType 概述

Bagisto 中的每种产品类型都继承自 AbstractType 类:

<?php

namespace Webkul\Product\Type;

abstract class AbstractType
{
    protected $product;
    protected $isStockable = true;
    protected $showQuantityBox = false;
    protected $haveSufficientQuantity = true;
    protected $canBeMovedFromWishlistToCart = true;
    protected $additionalViews = [];
    protected $skipAttributes = [];
}

要重写的关键方法

产品可售状态控制
isSaleable(): bool

控制产品是否显示为可购买:

public function isSaleable(): bool
{
    if (! parent::isSaleable()) {
        return false;
    }
    
    // Add custom availability logic
    return true;
}
haveSufficientQuantity(int $qty): bool

检查是否有足够的可用数量:

public function haveSufficientQuantity(int $qty): bool
{
    return true; // Custom logic based on subscription slots
}
库存控制
isStockable(): bool

确定产品是否使用库存跟踪:

public function isStockable(): bool
{
    return false; // Subscriptions don't use traditional inventory
}
totalQuantity(): int

返回可用总数量:

public function totalQuantity(): int
{
    return $this->product->subscription_slots ?? 0;
}
用户界面控制
showQuantityBox(): bool

控制是否显示数量输入框:

public function showQuantityBox(): bool
{
    return true;
}
定价方法
getProductPrices(): array

返回结构化定价数据:

public function getProductPrices(): array
{
    $basePrice = $this->product->price;
    $discount = $this->product->subscription_discount ?? 0;
    $finalPrice = $basePrice - ($basePrice * $discount / 100);
    
    return [
        'regular' => [
            'price' => core()->convertPrice($basePrice),
            'formatted_price' => core()->currency($basePrice),
        ],
        'final' => [
            'price' => core()->convertPrice($finalPrice),
            'formatted_price' => core()->currency($finalPrice),
        ],
    ];
}
getPriceHtml(): string

生成用于显示的价格 HTML:

public function getPriceHtml(): string
{
    return view('subscription::products.prices.subscription', [
        'product' => $this->product,
        'prices' => $this->getProductPrices(),
    ])->render();
}
验证方法
getTypeValidationRules(): array

返回产品类型专属字段的验证规则:

public function getTypeValidationRules(): array
{
    return [
        'subscription_frequency' => 'required|in:weekly,monthly,quarterly,yearly',
        'subscription_discount' => 'nullable|numeric|min:0|max:100',
        'subscription_duration' => 'nullable|integer|min:1',
        'subscription_slots' => 'required|integer|min:1',
    ];
}
管理后台界面自定义
$additionalViews 属性

指定产品编辑页面中的其他 Blade 视图:

protected $additionalViews = [
    'subscription::admin.catalog.products.edit.subscription-settings',
    'subscription::admin.catalog.products.edit.subscription-pricing',
];
$skipAttributes 属性

指定要跳过的属性:

protected $skipAttributes = [
    'weight',
    'dimensions',
];
购物车集成
prepareForCart(array $data): array

在将产品添加到购物车之前处理产品数据:

public function prepareForCart(array $data): array
{
    if (empty($data['subscription_frequency'])) {
        return 'Please select subscription frequency.';
    }
    
    $cartData = parent::prepareForCart($data);
    
    $cartData[0]['additional']['subscription_frequency'] = $data['subscription_frequency'];
    $cartData[0]['additional']['subscription_start_date'] = $data['start_date'] ?? now()->addDays(1)->format('Y-m-d');
    
    return $cartData;
}

@build:完整的订阅实现

软件包结构

packages/Webkul/SubscriptionProduct/
└── src/
    ├── Type/
    │   └── Subscription.php
    ├── Config/
    │   └── product-types.php
    └── Providers/
        └── SubscriptionServiceProvider.php

步骤 1:创建软件包结构

mkdir -p packages/Webkul/SubscriptionProduct/src/{Type,Config,Providers}

步骤 2:配置产品类型

文件: packages/Webkul/SubscriptionProduct/src/Config/product-types.php

<?php

return [
    'subscription' => [
        'key'   => 'subscription',
        'name'  => 'Subscription',
        'class' => 'Webkul\SubscriptionProduct\Type\Subscription',
        'sort'  => 5,
    ],
];

步骤 3:创建产品类型类

文件: packages/Webkul/SubscriptionProduct/src/Type/Subscription.php

<?php

namespace Webkul\SubscriptionProduct\Type;

use Webkul\Product\Helpers\Indexers\Price\Simple as SimpleIndexer;
use Webkul\Product\Type\AbstractType;

class Subscription extends AbstractType
{
    public function getPriceIndexer()
    {
        return app(SimpleIndexer::class);
    }
    
    public function isStockable(): bool
    {
        return false;
    }
    
    public function showQuantityBox(): bool
    {
        return true;
    }
    
    public function isSaleable(): bool
    {
        if (! parent::isSaleable()) {
            return false;
        }
        
        return true;
    }
    
    public function haveSufficientQuantity(int $qty): bool
    {
        return true;
    }
    
    public function totalQuantity(): int
    {
        return $this->product->subscription_slots ?? 0;
    }
    
    public function prepareForCart(array $data): array
    {
        if (empty($data['subscription_frequency'])) {
            return 'Please select subscription frequency.';
        }
        
        $cartData = parent::prepareForCart($data);
        
        $cartData[0]['additional']['subscription_frequency'] = $data['subscription_frequency'];
        $cartData[0]['additional']['subscription_start_date'] = $data['start_date'] ?? now()->addDays(1)->format('Y-m-d');
        
        return $cartData;
    }
}

步骤 4:创建服务提供程序

文件: packages/Webkul/SubscriptionProduct/src/Providers/SubscriptionServiceProvider.php

<?php

namespace Webkul\SubscriptionProduct\Providers;

use Illuminate\Support\ServiceProvider;

class SubscriptionServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->mergeConfigFrom(
            dirname(__DIR__) . '/Config/product-types.php',
            'product_types'
        );
    }

    public function boot(): void
    {
        //
    }
}

步骤 5:注册您的软件包

更新 composer.json
{
    "autoload": {
        "psr-4": {
            "Webkul\\SubscriptionProduct\\": "packages/Webkul/SubscriptionProduct/src"
        }
    }
}
更新自动加载器
composer dump-autoload
注册服务提供程序

在 bootstrap/providers.php 中:

<?php

return [
    App\Providers\AppServiceProvider::class,
    
    // ... other providers ...
    
    Webkul\SubscriptionProduct\Providers\SubscriptionServiceProvider::class,
];
清除缓存
php artisan optimize:clear

测试

php artisan tinker

# Test product type
>>> $product = \Webkul\Product\Models\Product::where('type', 'subscription')->first()
>>> $subscription = $product->getTypeInstance()

# Test methods
>>> $subscription->isStockable()        // Should return false
>>> $subscription->showQuantityBox()    // Should return true
>>> $subscription->isSaleable()         // Should return true

# Test cart preparation
>>> $cartData = $subscription->prepareForCart(['quantity' => 2, 'subscription_frequency' => 'monthly'])
>>> $cartData[0]['additional']  // Should show subscription data

内置产品类型参考

类型使用场景主要功能
简单基础产品标准定价、库存跟踪
可配置带有变体的产品变体管理、基于属性的定价
虚拟非实体产品无需配送
分组捆绑销售的相关产品捆绑定价、组件选择

关键文件参考

文件用途
Config/product-types.php产品类型注册
Type/ProductType.php产品类型类
Providers/ServiceProvider.php软件包注册
packages/Webkul/Product/src/Type/AbstractType.php基类

常见问题

  • 忘记在服务提供程序中合并配置
  • $key 与配置中的数组键不匹配
  • 未在 bootstrap/providers.php 中注册服务提供程序
  • 添加软件包后忘记运行 composer dump-autoload
  • 更改配置后未清除缓存
  • 重写时忘记调用 parent::isSaleable()
  • 未在 prepareForCart() 中正确处理购物车数据

评论

支持 Markdown