Skip to content

Commit

Permalink
Merge pull request #294 from scoutapp/implement-forgetCompiledOrNotEx…
Browse files Browse the repository at this point in the history
…pired

Implement forgetCompiledOrNotExpired method in Laravel 9
  • Loading branch information
asgrim authored Nov 8, 2022
2 parents 59cbba7 + 69aba76 commit 0901bfc
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 18 deletions.
26 changes: 13 additions & 13 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
SCOUT_APM_KEY: ${{ secrets.SCOUT_APM_KEY }}
run: |
echo "has_scout_apm_key_secret: ${{ env.SCOUT_APM_KEY != '' }}"
echo "::set-output name=has_scout_apm_key_secret::${{ env.SCOUT_APM_KEY != '' }}"
echo "has_scout_apm_key_secret=${{ env.SCOUT_APM_KEY != '' }}" >> $GITHUB_OUTPUT
base-unit:
name: "Unit tests"
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
env:
SCOUT_APM_KEY: ${{ secrets.SCOUT_APM_KEY }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand Down Expand Up @@ -111,7 +111,7 @@ jobs:
env:
SCOUT_APM_KEY: ${{ secrets.SCOUT_APM_KEY }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: Vampire/setup-wsl@v1
if: ${{ matrix.os == 'windows-latest' }}
- name: "Install PHP"
Expand Down Expand Up @@ -187,7 +187,7 @@ jobs:
env:
SCOUT_APM_KEY: ${{ secrets.SCOUT_APM_KEY }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand Down Expand Up @@ -221,7 +221,7 @@ jobs:
name: "Check coding standards"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand All @@ -239,7 +239,7 @@ jobs:
name: "Perform static analysis"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand All @@ -257,7 +257,7 @@ jobs:
name: "Check for Backward Compatibility breaks"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: "Install PHP"
Expand Down Expand Up @@ -304,7 +304,7 @@ jobs:
- { symfony-version: "6.*", php-version: "7.3" } # Symfony 6 requires 8.0+
- { symfony-version: "6.*", php-version: "7.4" } # Symfony 6 requires 8.0+
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand Down Expand Up @@ -366,7 +366,7 @@ jobs:
- {laravel-version: "9.*", php-version: "7.3"} # Laravel 9 requires 8.0+
- {laravel-version: "9.*", php-version: "7.4"} # Laravel 9 requires 8.0+
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand Down Expand Up @@ -430,7 +430,7 @@ jobs:
env:
SCOUT_APM_KEY: ${{ secrets.SCOUT_APM_KEY }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
path: scout-apm-php
- name: "Install PHP"
Expand Down Expand Up @@ -534,7 +534,7 @@ jobs:
env:
SCOUT_APM_KEY: ${{ secrets.SCOUT_APM_KEY }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
path: scout-apm-php
- name: "Install PHP"
Expand Down Expand Up @@ -611,7 +611,7 @@ jobs:
- {lumen-version: "9.*", php-version: "7.3"} # Lumen 9 requires 8.0+
- {lumen-version: "9.*", php-version: "7.4"} # Lumen 9 requires 8.0+
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: "Install PHP"
uses: shivammathur/setup-php@v2
with:
Expand Down Expand Up @@ -675,7 +675,7 @@ jobs:
steps:
- name: "Skip if SCOUT_APM_KEY secret is not available"
run: echo 'This job is skipped entirely as it needs SCOUT_APM_KEY set in secrets.'
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
path: scout-apm-php
- name: "Install PHP"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: actions/checkout@v3

- name: "Release"
uses: "laminas/automatic-releases@v1"
Expand Down
21 changes: 17 additions & 4 deletions src/Laravel/View/Engine/ScoutViewEngineDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,31 @@ function () use ($path, $data) {
}

/**
* Since Laravel has a nasty habit of exposing public API that is not defined in interfaces, we must expose the
* getCompiler method commonly used in the actual view engines.
* Note: this is a proxy for a method that does NOT exist in {@see \Illuminate\Contracts\View\Engine} but is still
* relied on by consumers of {@see \Illuminate\View\Engines\CompilerEngine::getCompiler}
*
* Unfortunately, we have to make all kinds of assertions due to this violation :/
* @link https://github.com/scoutapp/scout-apm-laravel/issues/8
*/
public function getCompiler(): CompilerInterface
{
// Assertion is necessary as normally this breaks LSP
assert(method_exists($this->engine, 'getCompiler'));
/** @psalm-suppress UndefinedInterfaceMethod */
$compiler = $this->engine->getCompiler();
assert($compiler instanceof CompilerInterface);

return $compiler;
}

/**
* Note: this is a proxy for a method that does NOT exist in {@see \Illuminate\Contracts\View\Engine} but is still
* relied on by consumers of {@see \Illuminate\View\Engines\CompilerEngine::forgetCompiledOrNotExpired}
*
* @link https://github.com/scoutapp/scout-apm-php/issues/293
*/
public function forgetCompiledOrNotExpired(): void
{
// Assertion is necessary as normally this breaks LSP
assert(method_exists($this->engine, 'forgetCompiledOrNotExpired'));
$this->engine->forgetCompiledOrNotExpired();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ public function compile($path): void
}
};
}

public function forgetCompiledOrNotExpired(): void
{
}
}
50 changes: 50 additions & 0 deletions tests/Unit/Laravel/View/Engine/ScoutViewEngineDecoratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@
use Illuminate\Contracts\Container\Container as ContainerInterface;
use Illuminate\Contracts\View\Engine;
use Illuminate\View\Compilers\CompilerInterface;
use Illuminate\View\Engines\CompilerEngine;
use Illuminate\View\Engines\EngineResolver;
use Illuminate\View\Factory as ViewFactory;
use Illuminate\View\ViewException;
use PHPUnit\Framework\Constraint\IsType;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionMethod;
use Scoutapm\Laravel\View\Engine\ScoutViewEngineDecorator;
use Scoutapm\ScoutApmAgent;
use Spatie\LaravelIgnition\Views\BladeSourceMapCompiler;
use Spatie\LaravelIgnition\Views\ViewExceptionMapper;

use function class_exists;
use function get_class;
use function method_exists;
use function sprintf;
use function uniqid;

/** @covers \Scoutapm\Laravel\View\Engine\ScoutViewEngineDecorator */
Expand Down Expand Up @@ -121,6 +127,50 @@ public function testGetCompilerWillProxyToRealEngineGetCompilerMethd(): void
self::assertSame($compiler, $this->viewEngineDecorator->getCompiler());
}

public function testForgetCompiledOrNotExpiredWillProxyToRealEngineForgetCompiledOrNotExpiredMethd(): void
{
$this->realEngine
->expects(self::once())
->method('forgetCompiledOrNotExpired');

$this->viewEngineDecorator->forgetCompiledOrNotExpired();
}

/**
* ScoutViewEngineDecorator is designed to be generic decorator for {@see \Illuminate\Contracts\View\Engine}
* implementations. However, specific implementations such as {@see \Illuminate\View\Engines\CompilerEngine} keep
* having public API added that is NOT part of the engine, therefore breaking LSP.
*
* @link https://github.com/scoutapp/scout-apm-laravel/issues/8
* @link https://github.com/scoutapp/scout-apm-php/issues/293
*
* This test aims to ensure that when public methods are added to {@see \Illuminate\View\Engines\CompilerEngine}
* then we have implemented it in {@see \Scoutapm\Laravel\View\Engine\ScoutViewEngineDecorator}.
*/
public function testScoutViewEngineDecoratorImplementsAllPublicApiOfCompilerEngine(): void
{
$realCompilerEngineMethods = (new ReflectionClass(CompilerEngine::class))
->getMethods(ReflectionMethod::IS_PUBLIC);

foreach ($realCompilerEngineMethods as $compilerEngineMethod) {
if ($compilerEngineMethod->isConstructor()) {
continue;
}

$compilerEngineMethodName = $compilerEngineMethod->getShortName();

self::assertTrue(
method_exists($this->viewEngineDecorator, $compilerEngineMethodName),
sprintf(
'Method "%s" did not exist on %s, but exists in %s',
$compilerEngineMethodName,
get_class($this->viewEngineDecorator),
CompilerEngine::class
)
);
}
}

public function testSpatieLaravelIgnitionCompatibility(): void
{
if (! class_exists(ViewExceptionMapper::class)) {
Expand Down

0 comments on commit 0901bfc

Please sign in to comment.