interitty/output-buffer-manager

Output buffer manager brings a safe way to work with outputs.

v1.0.2 2023-12-28 22:26 UTC

This package is auto-updated.

Last update: 2024-03-28 23:05:30 UTC


README

Output buffer manager brings a safe way to work with outputs.

Requirements

Installation

The best way to install interitty/output-buffer-manager is using Composer:

composer require interitty/output-buffer-manager

Then register the extension in the Nette config file:

# app/config/config.neon
extensions:
    outputBufferManager: Interitty\OutputBufferManager\Nette\DI\OutputBufferManagerExtension

Features

For more complex applications where the work with the output buffer is needed, this package helps to organize individual handlers. The naming of each handler is requested, because it helps to prevent very difficult-to-detect and unnecessary problems. It also allows for an easy route to multiple concurrent handlers at the same moment. Output buffer manager does nothing until requested. Because of that, it can be registered as a service in the dependency injection container or service locator and be used wherever it is needed. In the following examples, the new instance of OutputBufferManager class is created for simplification. The manager works with the so-called "handlers", which are anonymous functions or callbacks. These "handlers" are encapsulated into objects of class Handler, that represent simple implementation of the HandlerInterface, which is used internally. This mechanism provides additional events, that can be useful in some cases.

Example: catch content into a variable

The following example catches any content that was sent to the output and appends it to the given $output variable. It also shows, that "handler" can be defined as an anonymous functions Because the handler doesn't have a return value, nothing will be sent to the output or another registered handler.

$output = null;
$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(string $bufferOutput) use(&$output): string {
    $output .= $bufferOutput;
    return '';
});

// Any content that was sent to the output
echo 'testContent';

$outputBufferManager->end('…');

Example: catch content into property

The following example catches any content that was sent to the output and appends it into the Example::$output property. It also shows, that "handler" can be defined as a callback.

class Example
{

    public $output;

    public function __construct(): void
    {
        $outputBufferManager = new OutputBufferManager();
        $outputBufferManager->begin('…', [$this, 'handleCatchContent']);

        // Any content that was sent to the output
        echo 'testContent';

        $outputBufferManager->end('…');
    }

    public function handleCatchContent(string $bufferOutput): string
    {
        $this->output .= $bufferOutput;
        return '';
    }
}

Example: proxy content into a variable

The following example proxy any content that was sent to the output and appends it into the given $output variable. Because the handler has the return value, everything will be also sent to the output or another registered handler.

$output = null;
$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(string $bufferOutput) use(&$output): string {
    $output .= $bufferOutput;
    return $bufferOutput;
});

// Any content that was sent to the output
echo 'testContent';

$outputBufferManager->end('…');

Example: flush content of output buffer

In some cases, it could be useful to manually flush the content of the output buffer into handlers. For that purpose, there is a flush method on the OutputBufferManager object. As with other methods, it also expects the name of the current handler to prevent ugly problems.

$outputBufferManager = new OutputBufferManager();

// in some cases like in the foreach cycle …
$outputBufferManager->flush('…');

$outputBufferManager->end('…');

When things go wrong

In some cases is possible to see the following exceptions.

LogicException: Output buffer handler "…" is already registered

As the message of the exception says, another handler with the same name was registered before. The core of the problem is similar to the following code.

$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(): string {return '';});
$outputBufferManager->begin('…', function(): string {return '';});

There can be just one handler of the same name at the same time.

Solution

The solution is to use a different (unique) name or stop using the last one and begin work with the new one.

$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(): string {return '';});
// warning: calling end flush unflushed data
$outputBufferManager->end('…');

$outputBufferManager->begin('…', function(): string {return '';});

LogicException: Current output buffer manager is not OutputBufferManager

The core of the problem is, that OutputBufferManager is not the current Output buffer handler. It can happen when OutputBufferManager was not started yet.

$outputBufferManager = new OutputBufferManager();

// Forgotten call of $outputBufferManager->begin('…', function(): string {return '';});

$outputBufferManager->end('…');

Another possibility is that there is a registered different handler than OutputBufferManager.

$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(): string {return '';});

// Maybe the old mechanism of the Output buffer was forgotten in the code
ob_start(function(): string {return '';});

$outputBufferManager->end('…');

Solution

The possible solution depends on the use case:

  • Replace old handlers with the OutputBufferManager.
  • Flush the old handler ( ob_end_clean or ob_end_flush ) to fall back into OutputBufferManager.
  • Register new OutputBufferManager via OutputBufferManager::begin.

LogicException: Expected output buffer handler "…" is not registered

The core of the problem is mostly in the misspelled name of the handler.

$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('...', function(): string {return '';});

$outputBufferManager->end('…');

Solution

Fix the name of the expected handler. It is better to use constants for handler names to prevent this problem.


define('OUTPUT_BUFFER_MAIN', '…');
$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin(OUTPUT_BUFFER_MAIN, function(): string {return '';});

$outputBufferManager->end(OUTPUT_BUFFER_MAIN);

LogicException: Current output buffer handler "..." is not expected "…"

The core of the problem is mostly in the forgotten termination of the last used handler or crossing the call.

$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(): string {return '';});
$outputBufferManager->begin('...', function(): string {return '';});

// Somebody forgot call $outputBufferManager->end('...');

$outputBufferManager->end('…');

Solution

Add forgotten termination of the previous handler or correct the position of the handler calling.

$outputBufferManager = new OutputBufferManager();
$outputBufferManager->begin('…', function(): string {return '';});
$outputBufferManager->end('…');

$outputBufferManager->begin('...', function(): string {return '';});
$outputBufferManager->end('...');