flytachi/winter-cdo 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

flytachi/winter-cdo

Composer 安装命令:

composer require flytachi/winter-cdo

包简介

Extended, type-safe PDO wrapper for PostgreSQL, MySQL/MariaDB and Oracle with a composable, injection-safe query builder.

README 文档

README

Latest Version on Packagist PHP Version Require Software License

CDO (Connection Data Object) — an extended PDO wrapper for type-safe, parameterised database operations with a composable query builder.

Full documentation: https://winterframe.net/packages/cdo

Requirements

  • PHP >= 8.3
  • ext-pdo
  • psr/log ^3.0

Installation

composer require flytachi/winter-cdo

Supported Databases

Database insert insertGroup upsert upsertGroup update delete
PostgreSQL
MySQL / MariaDB
Oracle ⚠️

Quick Start

1. Define a configuration

Extend MySqlDbConfig or PgDbConfig and fill credentials in setUp():

use Flytachi\Winter\Cdo\Config\PgDbConfig;

class AppDb extends PgDbConfig
{
    public function setUp(): void
    {
        $this->host     = env('DB_HOST', 'localhost');
        $this->port     = (int) env('DB_PORT', 5432);
        $this->database = env('DB_NAME', 'myapp');
        $this->username = env('DB_USER', 'postgres');
        $this->password = env('DB_PASS', '');
    }
}

For a one-off connection without a dedicated class, use the inline PgDbCall / MySqlDbCall / DbCall constructors — see Configuration docs.

2. Get a connection

$cdo = ConnectionPool::db(AppDb::class);

3. Run operations

use Flytachi\Winter\Cdo\Qb;

// Insert — returns the generated primary key:
$id = $cdo->insert('users', [
    'name'  => 'Alice',
    'email' => 'alice@example.com',
]);

// Update — returns affected row count:
$cdo->update('users',
    ['name' => 'Alice Smith'],
    Qb::eq('id', $id)
);

// Delete — returns deleted row count:
$cdo->delete('users', Qb::eq('id', $id));

// Batch insert:
$cdo->insertGroup('users', $usersArray, chunkSize: 500);

// Upsert (insert or update on conflict):
$cdo->upsert('products',
    ['sku' => 'ABC-001', 'price' => 9.99, 'stock' => 50],
    conflictColumns: ['sku'],
    updateColumns: ['price' => ':new', 'stock' => ':current + :new']
);

Qb — Query Builder

Qb builds safe, parameterised SQL WHERE fragments. Every value is bound via a named placeholder — no string interpolation, no injection risk.

Column names, however, are injected verbatim (they cannot be bound). Never pass user input as a column name: Qb::eq('status', $userInput) is safe, Qb::eq($userInput, 'active') is a SQL-injection vector.

// Simple condition:
Qb::eq('status', 'active')
// → status = :iqb0

// Compound condition:
$where = Qb::and(
    Qb::eq('status', 'active'),
    Qb::gte('age', 18),
    Qb::isNull('banned_at'),
);
// → status = :iqb0 AND age >= :iqb1 AND banned_at IS NULL

Operator reference

Category Methods SQL result
Comparison eq, neq, gt, gte, lt, lte col = :x, col != :x, …
NULL isNull, isNotNull col IS NULL, col IS NOT NULL
NULL-safe nsEq col <=> :x (MySQL/MariaDB)
Set in, notIn col IN (:a, :b), col NOT IN (…)
Pattern like, notLike col LIKE :x, col NOT LIKE :x
Range between, notBetween col BETWEEN :a AND :b
Range (inverted) betweenBy, notBetweenBy :x BETWEEN col1 AND col2
Logical and, or, xor a AND b, a OR b, a XOR b
Grouping clip (condition)
CASE case CASE WHEN … THEN … END
Raw raw verbatim SQL with optional binds

Operator precedence — always use clip with mixed AND/OR

// ❌ Wrong — SQL reads as (published AND role='editor') OR role='admin':
Qb::and(
    Qb::eq('published', true),
    Qb::or(Qb::eq('role', 'editor'), Qb::eq('role', 'admin')),
)

// ✅ Correct — clip enforces the right grouping:
Qb::and(
    Qb::eq('published', true),
    Qb::clip(
        Qb::or(Qb::eq('role', 'editor'), Qb::eq('role', 'admin'))
    ),
)
// → published IS TRUE AND (role = :iqb0 OR role = :iqb1)

Dynamic filters

// null conditions are silently skipped:
$where = Qb::and(
    Qb::eq('status', 'active'),
    $minAge  !== null ? Qb::gte('age', $minAge)   : null,
    $country !== null ? Qb::eq('country', $country) : null,
    Qb::in('tag_id', $tagIds),   // skipped when $tagIds is []
);

Named binds — share one placeholder across conditions

$uid = new CDOBind('uid', $currentUserId);

$where = Qb::or(
    Qb::eq('author_id',   $uid),
    Qb::eq('reviewer_id', $uid),
    Qb::eq('assignee_id', $uid),
);
// → author_id = :uid OR reviewer_id = :uid OR assignee_id = :uid

Upsert Placeholders

Token PostgreSQL MySQL / MariaDB
:new EXCLUDED.column VALUES(column)
:current table.column column
$cdo->upsertGroup('inventory', $items,
    conflictColumns: ['warehouse_id', 'product_id'],
    updateColumns: [
        'cost'       => ':new',
        'quantity'   => ':current + :new',
        'updated_at' => 'NOW()',
    ]
);

Error Handling

All failures throw CDOException, which wraps the original PDOException as its $previous cause (preserving SQLSTATE code and driver message):

use Flytachi\Winter\Cdo\Connection\CDOException;

try {
    $cdo->insert('users', $data);
} catch (CDOException $e) {
    $sqlstate = $e->getPrevious()?->getCode();  // e.g. "23505" (PG unique violation)
    // handle or re-throw
}

Documentation

Full reference documentation is at https://winterframe.net/packages/cdo

Local docs in docs/:

File Topic
01-configuration.md Config classes, inline Call classes
02-connection-pool.md ConnectionPool, health checks
03-cdo.md All CDO DML methods
04-cdo-statement.md Type binding, object serialisation
05-exceptions.md CDOException, SQLSTATE reference
06-cdobind.md CDOBind — named parameters
07-comparison-operators.md eq, neq, gt, gte, lt, lte, nsEq
08-null-checks.md isNull, isNotNull
09-set-operators.md in, notIn
10-pattern-matching.md like, notLike
11-range-operators.md between, betweenBy, notBetween, notBetweenBy
12-logical-operators.md and, or, xor, clip
13-mutable-methods.md addAnd, addOr, addXor
14-case-expression.md CASE WHEN … END
15-special.md raw, empty
16-advanced-examples.md Real-world combinations

License

MIT License. See LICENSE.

flytachi/winter-cdo 适用场景与选型建议

flytachi/winter-cdo 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 544 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 12 月 17 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 flytachi/winter-cdo 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-12-17