Issue: Migrate to shared presentation layer from horde/cli
Context
horde/components currently has its own presentation layer implementation:
src/
├── Output.php # Facade
├── Output/
│ ├── Presenter.php # Interface
│ ├── PresenterFactory.php # Auto-detection
│ └── Presenter/
│ ├── Classic.php
│ ├── Ci.php
│ └── Unicode.php
This was implemented first as a proof-of-concept, but should now be extracted to horde/cli for sharing across all Horde CLI tools.
Related Issues:
- horde/cli#X - Add pluggable presentation layer (destination)
- horde/cli_modular#X - Integrate presentation layer
- horde/hordectl#X - Adopt presentation layer
Problem
Having presentation layer in components means:
- Code duplication - Other tools must reimplement or copy
- Maintenance burden - Bug fixes don't propagate automatically
- Inconsistency - Each tool might deviate from the pattern
- Components-specific - Coupled to components, not reusable
Proposed Migration
Phase 1: Extract to horde/cli
Move presentation layer from components to cli:
Source (components):
components/src/Output/Presenter.php
components/src/Output/PresenterFactory.php
components/src/Output/Presenter/*.php
Destination (cli):
cli/src/Output/Presenter.php
cli/src/Output/PresenterFactory.php
cli/src/Output/Presenter/*.php
Changes needed:
- Namespace:
Horde\Components\Output → Horde\Cli\Output
- No interface changes
- Tests move with implementation
Phase 2: Update components to use horde/cli
Once extracted, components depends on cli implementation:
composer.json:
{
"require": {
"horde/cli": "^3.0" // Version with presenter support
}
}
Output.php facade:
namespace Horde\Components;
use Horde\Cli\Output\Presenter;
use Horde\Cli\Output\PresenterFactory; // From horde/cli now
class Output
{
private readonly Presenter $_presenter;
public function __construct(private readonly \Horde_Cli $_cli, $options)
{
// Use factory from horde/cli
$this->_presenter = PresenterFactory::create($_cli, $options);
}
// ... rest unchanged
}
Phase 3: Remove Local Implementation
Delete from components:
src/Output/Presenter.php → moved to horde/cli
src/Output/PresenterFactory.php → moved to horde/cli
src/Output/Presenter/ → moved to horde/cli
Keep in components:
src/Output.php → facade (now uses horde/cli)
Backward Compatibility
For components users: Zero breaking changes
Components\Output facade stays
- API unchanged
- Presenters work identically
For code inspection:
- Presenters now in
Horde\Cli\Output namespace
- Accessible to all Horde CLI tools
Benefits
For components:
- Smaller codebase
- Bug fixes from upstream (horde/cli)
- Consistent with other tools
For Horde ecosystem:
- Single implementation
- All CLI tools benefit
- Easier to contribute improvements
For maintenance:
- One place to fix bugs
- One place to add features (e.g., JSON presenter)
- Consistent testing
Implementation Plan
Step 1: Coordinate with horde/cli
Wait for horde/cli#X to be implemented:
- Presenter interface added
- Factory with auto-detection added
- Presenter implementations added
- Tests added
Step 2: Update components composer.json
{
"require": {
"horde/cli": "^3.0"
}
}
Step 3: Update Output.php
Change imports from local to horde/cli:
// Before
use Horde\Components\Output\Presenter;
use Horde\Components\Output\PresenterFactory;
// After
use Horde\Cli\Output\Presenter;
use Horde\Cli\Output\PresenterFactory;
Step 4: Remove Local Files
rm -rf src/Output/Presenter.php
rm -rf src/Output/PresenterFactory.php
rm -rf src/Output/Presenter/
Step 5: Update Tests
- Update test imports
- Ensure Output facade still works
- Integration tests with horde/cli presenters
Step 6: Update Documentation
- Note the migration in CHANGES/changelog
- Update README if it mentions presenters
- Document that presenters come from horde/cli
Testing Strategy
Before Migration:
- Snapshot current test output
- Document all presenter behaviors
After Migration:
- All tests pass with horde/cli presenters
- Output unchanged from user perspective
- Integration tests confirm compatibility
Regression Testing:
- Test all three presenters (Classic, CI, Unicode)
- Test auto-detection in different environments
- Test with --format flag
- Test with --nocolor flag
Migration Checklist
Example: Before vs After
Before (Local Implementation)
components/
├── src/
│ ├── Output.php # Facade
│ └── Output/
│ ├── Presenter.php # Local interface
│ ├── PresenterFactory.php # Local factory
│ └── Presenter/
│ ├── Classic.php # Local implementation
│ ├── Ci.php # Local implementation
│ └── Unicode.php # Local implementation
└── composer.json
"require": {
"horde/cli": "^2.0" # Old version
}
After (Shared Implementation)
components/
├── src/
│ └── Output.php # Facade (uses horde/cli)
└── composer.json
"require": {
"horde/cli": "^3.0" # New version with presenters
}
cli/
├── src/
│ └── Output/
│ ├── Presenter.php # Interface (shared)
│ ├── PresenterFactory.php # Factory (shared)
│ └── Presenter/
│ ├── Classic.php # Implementation (shared)
│ ├── Ci.php # Implementation (shared)
│ └── Unicode.php # Implementation (shared)
Related Issues
- horde/cli#X - Add pluggable presentation layer (prerequisite)
- horde/cli_modular#X - Integrate presentation layer
- horde/hordectl#X - Adopt presentation layer
Timeline
- Q2 2026: Wait for horde/cli#X implementation
- Q3 2026: Migrate components to use shared layer
- Q3 2026: Remove local implementation
- Q4 2026: Release and document migration
Success Criteria
- ✅ components uses horde/cli presenters
- ✅ Local presenter code removed
- ✅ All tests pass
- ✅ Zero breaking changes for components users
- ✅ Other tools can now use presenters from horde/cli
- ✅ Single source of truth for presentation logic
Issue: Migrate to shared presentation layer from horde/cli
Context
horde/components currently has its own presentation layer implementation:
This was implemented first as a proof-of-concept, but should now be extracted to horde/cli for sharing across all Horde CLI tools.
Related Issues:
Problem
Having presentation layer in components means:
Proposed Migration
Phase 1: Extract to horde/cli
Move presentation layer from components to cli:
Source (components):
Destination (cli):
Changes needed:
Horde\Components\Output→Horde\Cli\OutputPhase 2: Update components to use horde/cli
Once extracted, components depends on cli implementation:
composer.json:
{ "require": { "horde/cli": "^3.0" // Version with presenter support } }Output.php facade:
Phase 3: Remove Local Implementation
Delete from components:
Keep in components:
Backward Compatibility
For components users: Zero breaking changes
Components\Outputfacade staysFor code inspection:
Horde\Cli\OutputnamespaceBenefits
For components:
For Horde ecosystem:
For maintenance:
Implementation Plan
Step 1: Coordinate with horde/cli
Wait for horde/cli#X to be implemented:
Step 2: Update components composer.json
{ "require": { "horde/cli": "^3.0" } }Step 3: Update Output.php
Change imports from local to horde/cli:
Step 4: Remove Local Files
Step 5: Update Tests
Step 6: Update Documentation
Testing Strategy
Before Migration:
After Migration:
Regression Testing:
Migration Checklist
Example: Before vs After
Before (Local Implementation)
After (Shared Implementation)
Related Issues
Timeline
Success Criteria