quellabs/canvas
Composer 安装命令:
composer require quellabs/canvas
包简介
A modern, lightweight PHP framework with contextual containers, automatic service discovery, and ObjectQuel ORM integration
README 文档
README
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 acanvas()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 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 quellabs/canvas 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
PHP Framework HLEB2 is the foundation of the web application. Provides ease of development and application performance.
Shoot aims to make providing data to your templates more manageable
Supporing Symfony's DependencyInjection component for your symfony1 project
A Processor for Markup written in PHP. Allows extraction of Markup into a data structure, orchestrated nested manipulation of said structure, and output as (optimized) Markup.
Powerful class discovery system for Laravel with attribute-based scanning, directory traversal, and monorepo support
Melis Platform Templating Plugin Creator
统计信息
- 总下载量: 387
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 14
- 点击次数: 14
- 依赖项目数: 3
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-05-23