quellabs/canvas 问题修复 & 功能扩展

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

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

quellabs/canvas

Composer 安装命令:

composer require quellabs/canvas

包简介

A modern, lightweight PHP framework with contextual containers, automatic service discovery, and ObjectQuel ORM integration

README 文档

README

Packagist PHPStan License

A PHP framework built for real-world projects — especially the messy ones. Canvas drops into existing PHP codebases without forcing a rewrite, while giving new projects a clean, annotation-driven architecture with aspect-oriented programming and a readable ORM.

The legacy problem

Most frameworks assume you're starting fresh. Canvas doesn't. Point it at your existing application, and it takes over routing while your old .php files keep working:

// config/app.php
return [
    'legacy_enabled' => true,
    'legacy_path'    => dirname(__FILE__) . "/../legacy"
];

Canvas checks its own routes first. Unmatched URLs fall through to your legacy files — every existing page keeps working from day one. Your legacy code can immediately use Canvas services:

// legacy/admin/dashboard.php — your existing file, now with Canvas services
$users = canvas('EntityManager')->findBy(User::class, ['active' => true]);

Legacy files using header(), die(), and exit() are automatically preprocessed to work within Canvas's request/response flow. The preprocessing is recursive — included files are transformed too, and results are cached.

Migrate one route at a time. When a Canvas controller claims a URL, it takes precedence over the legacy file. When every route is migrated, set legacy_enabled to false.

Cross-cutting concerns without the mess

Here's what a controller looks like when authentication, caching, and rate limiting are tangled into business logic:

// The usual approach
public function manage() {
    if (!$this->auth->isAuthenticated()) {
        return redirect('/login');
    }

    $key = 'users_' . md5(serialize($params));
    if ($cached = $this->cache->get($key)) {
        return $cached;
    }

    if ($this->rateLimiter->tooManyAttempts($ip, 100)) {
        return response('Too many requests', 429);
    }

    $users = $this->em()->findBy(User::class, ['active' => true]);
    $result = $this->render('admin/users.tpl', compact('users'));
    $this->cache->set($key, $result, 300);
    return $result;
}

Canvas separates cross-cutting concerns into aspects — reusable classes applied via annotations:

// Canvas: business logic only, concerns declared as aspects
/**
 * @Route("/admin/users")
 * @InterceptWith(RequireAuthAspect::class, priority=100)
 * @InterceptWith(CacheAspect::class, ttl=300)
 * @InterceptWith(RateLimitAspect::class, limit=100, window=3600)
 */
public function manage() {
    $users = $this->em()->findBy(User::class, ['active' => true]);
    return $this->render('admin/users.tpl', compact('users'));
}

Three lines of business logic. Authentication, caching, and rate limiting are declared, not coded. Each aspect is a standalone class — BeforeAspect for auth checks, AroundAspect for caching, AfterAspect for logging:

class RequireAuthAspect implements BeforeAspect {
    public function __construct(private AuthService $auth) {}

    public function before(MethodContextInterface $context): ?Response {
        if (!$this->auth->isAuthenticated()) {
            return new RedirectResponse('/login');
        }
        return null; // proceed to method
    }
}

Aspects inherit through controller hierarchies — apply @InterceptWith on a base class and every child controller gets it automatically. Priority ordering controls execution sequence within each inheritance level.

ObjectQuel ORM

Canvas integrates with ObjectQuel through the quellabs/canvas-objectquel package. Simple lookups use familiar find and findBy methods. Complex queries use ObjectQuel's declarative syntax:

$results = $this->em()->executeQuery("
    range of p is App\\Entity\\Post
    range of u is App\\Entity\\User via p.authorId
    retrieve (p, u.name) where p.title = /^Tech/i
    sort by p.publishedAt desc
    window 0 using window_size 20
");

Pattern matching, regex, full-text search, and relationship traversal are first-class query expressions — not raw SQL escapes. ObjectQuel can also join database entities with JSON files in a single query via json_source(), something no other PHP ORM supports.

How to Install

# New project
composer create-project quellabs/canvas-skeleton my-app

# Existing project
composer require quellabs/canvas

Quick start

class BlogController extends BaseController {

    /**
     * @Route("/posts/{id:int}")
     */
    public function show(int $id) {
        $post = $this->em()->find(Post::class, $id);
        return $this->render('post.tpl', compact('post'));
    }
}

Controllers are discovered automatically through Composer metadata. Routes are defined with annotations. Typed route parameters ({id:int}) are validated before your method runs. No configuration files, no route registration.

Canvas uses Smarty as its default template engine. Twig support is available through a separate package.

Features

  • Legacy-first integration — wrap existing PHP apps with route fallthrough, automatic preprocessing of header()/die()/exit(), and a canvas() helper for accessing services from legacy code
  • Aspect-oriented programming — Before, Around, and After aspects with annotation parameters, priority ordering, and inheritance through controller hierarchies
  • ObjectQuel ORM — declarative query language with pattern matching, hybrid JSON sources, and Data Mapper architecture
  • Contextual dependency injection — resolve different interface implementations based on request context, without conditional logic in your code
  • Signal/slot event system — Qt-style decoupled service communication with type checking and priority-based handlers
  • Task scheduling — cron-style background jobs with timeouts and concurrent execution handling
  • Validation & sanitization — declarative rules applied as aspects, keeping controllers clean
  • Visual inspector — debug bar with database queries, request analysis, and custom panels
  • CLI tooling — route listing, route matching, task management, asset publishing, entity generation

Documentation

Full docs, guides, and API reference: canvasphp.com/docs

Contributing

Bug reports and feature requests via GitHub issues. PRs welcome — fork, branch, follow PSR-12, add tests.

Support

If Canvas saves you time, consider sponsoring development.

License

MIT

quellabs/canvas 适用场景与选型建议

quellabs/canvas 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 387 次下载、GitHub Stars 达 14, 最近一次更新时间为 2025 年 05 月 23 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 quellabs/canvas 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-05-23