Skip to content

Migrate to shared presentation layer from horde/cli #12

Description

@ralflang

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\OutputHorde\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

  • horde/cli#X implemented and released
  • Update components composer.json to require horde/cli ^3.0
  • Update Output.php imports
  • Remove local Presenter files
  • Update tests
  • Update documentation
  • Verify all presenters work
  • Verify auto-detection works
  • Release new components version

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions