PHP code example of lzpeng / hyperf-cycle

1. Go to this page and download the library: Download lzpeng/hyperf-cycle library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

lzpeng / hyperf-cycle example snippets




declare(strict_types=1);

use Cycle\Database\Config\MySQL\TcpConnectionConfig;
use Lzpeng\HyperfCycle\Config\MySQLDriverConfig;
use function Hyperf\Support\env;

return [
    'default' => 'default',
    'databases' => [
        'default' => ['connection' => 'default'],
    ],
    'connections' => [
        'default' => new MySQLDriverConfig(
            connection: new TcpConnectionConfig(
                database: env('DB_DATABASE', 'test'),
                host: env('DB_HOST', 'localhost'),
                port: env('DB_PORT', 3306),
                user: env('DB_USER', 'test'),
                password: env('DB_PASSWORD', ''),
                charset: env('DB_CHARSET', 'utf8mb4'),
            ),
            reconnect: true,
            queryCache: true,
            options: [],
            poolOptions: [
                'min_connections' => env('DB_MIN_CONNECTIONS', 1),
                'max_connections' => env('DB_MAX_CONNECTIONS', 10),
                'connect_timeout' => env('DB_CONNECT_TIMEOUT', 10.0),
                'wait_timeout' => env('DB_WAIT_TIMEOUT', 3.0),
                'heartbeat' => env('DB_HEARTBEAT', -1),
                'max_idle_time' => env('DB_MAX_IDLE_TIME', 60.0),
            ],
        ),
    ],
];

use Lzpeng\HyperfCycle\ORMFactory;

$ormFactory = $container->get(ORMFactory::class);

$orm = $ormFactory->orm();
$em = $ormFactory->entityManager();

use Cycle\Database\Config\MySQL\TcpConnectionConfig;
use Cycle\ORM\Entity\Behavior\EventDrivenCommandGenerator;
use Cycle\ORM\Schema;
use Lzpeng\HyperfCycle\Config\DatabaseConfig;
use Lzpeng\HyperfCycle\Config\MySQLDriverConfig;
use Lzpeng\HyperfCycle\DatabaseManager;
use Lzpeng\HyperfCycle\ORMFactory;

$databaseManager = new DatabaseManager(
    new DatabaseConfig([
        'default' => 'default',
        'databases' => [
            'default' => ['connection' => 'mysql'],
        ],
        'connections' => [
            'mysql' => new MySQLDriverConfig(
                connection: new TcpConnectionConfig(
                    database: 'spiral',
                    host: '127.0.0.1',
                    port: 3306,
                    user: 'spiral',
                    password: '',
                ),
                queryCache: true,
                poolOptions: [
                    'min_connections' => 1,
                    'max_connections' => 20,
                    'connect_timeout' => 10.0,
                    'wait_timeout' => 3.0,
                    'heartbeat' => -1,
                    'max_idle_time' => 60.0,
                ],
            ),
        ],
    ])
);

$container = /** 获取容器 */;
$schemaConfig = /** Cycle Schema 配置 */;

$schema = new Schema($schemaConfig);
$commandGenerator = new EventDrivenCommandGenerator($schema, $container);

$ormFactory = new ORMFactory(
    databaseManager: $databaseManager,
    schema: $schema,
    commandGenerator: $commandGenerator,
);

$orm = $ormFactory->orm();
$em = $ormFactory->entityManager();

use Cycle\Database\DatabaseInterface;
use Lzpeng\HyperfCycle\DatabaseManager;

/**
 * 产品数量管理器.
 */
class QuantityManager implements QuantityManagerInterface
{
    private DatabaseInterface $database;

    public function __construct(private DatabaseManager $databaseManager)
    {
        // 错误:作为属性持久化数据库连接会导致连接泄露问题或事务问题
        $this->database = $this->databaseManager->database();
    }

    public function decrease(Id $productId, Id $skuId, Quantity $quantity): void
    {
        $affected = $this->database->execute(
            'UPDATE `shop_product_sku` SET `quantity` = `quantity` - ? WHERE `id` = ? AND `product_id` = ? AND `quantity` > 0',
            [
                $quantity->toInt(),
                $skuId,
                $productId,
            ]
        );

        if ($affected === 0) {
            throw DomainException::from('库存不足,无法减少库存量', [
                'id' => $productId,
            ]);
        }
    }

    // ...
}

/**
 * 下单.
 */
class PlaceOrderCommand
{
    public function __construct(
        private SkuRepositoryInterface $skuRepository,
        private UserRepositoryInterface $userRepository,
        private OrderRepositoryInterface $orderRepository,
        private OrderFactory $orderFactory,
        private QuantityManagerInterface $quantityManager,
        private TransactionInterface $transaction,
    ) {
    }

    public function execute(
        Id $userId,
        int $productId,
        int $skuId,
        int $quantity,
        array $fulfillmentData,
    ): array {
        // ...

        $order = $this->orderFactory->create($user, $product, $sku, $quantity);

        $this->transaction->execute(function () use ($order, $user) {
            $this->orderRepository->save($order);

            // 由于QuantityManager将数据库连接作为属性, 使用的不是与orderRepository同一个连接, 导致事务失效
            $this->quantityManager->decrease($order->productId(), $order->skuId(), $order->quantity());
        });

        // ...
    }
}

use Lzpeng\HyperfCycle\DatabaseManager;

/**
 * 产品数量管理器.
 */
class QuantityManager implements QuantityManagerInterface
{
    public function __construct(private DatabaseManager $databaseManager)
    {
    }

    public function decrease(Id $productId, Id $skuId, Quantity $quantity): void
    {
        // 使用时才获取数据库连接,确保连接能够正确回收;
        // 同一协程内的连接实例是同一个,事务能够正常工作
        $affected = $this->databaseManager->database()->execute(
            'UPDATE `shop_product_sku` SET `quantity` = `quantity` - ? WHERE `id` = ? AND `product_id` = ? AND `quantity` > 0',
            [
                $quantity->toInt(),
                $skuId,
                $productId,
            ]
        );

        if ($affected === 0) {
            throw DomainException::from('库存不足,无法减少库存量', [
                'id' => $productId,
            ]);
        }
    }

    // ...
}
bash
php bin/hyperf.php vendor:publish lzpeng/hyperf-cycle