Skip to content

Adding Autowireable interfaces & docs for reset() #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,43 @@ and `build/entry1.js`, then `encore_entry_script_tags()` is equivalent to:
If you want more control, you can use the `encore_entry_js_files()` and
`encore_entry_css_files()` methods to get the list of files needed, then
loop and create the `script` and `link` tags manually.

## Rendering Multiple Times in a Request (e.g. to Generate a PDF)

When you render your script or link tags, the bundle is smart enough
not to repeat the same JavaScript or CSS file within the same request.
This prevents you from having duplicate `<link>` or `<script>` tags
if you render multiple entries that both rely on the same file.

In some cases, however, you may want to render the script & link
tags for the same entry multiple times in a request. For example,
if you render multiple Twig templates to create multiple PDF files
during a single request.

In that case, before each render, you'll need to "reset" the internal
cache so that the bundle re-renders CSS or JS files that it previously
rendered. For example, in a controller:

```php
// src/Controller/SomeController.php

use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;

class SomeController
{
public function index(EntrypointLookupInterface $entrypointLookup)
{
$entrypointLookup->reset();
// render a template

$entrypointLookup->reset();
// render another template

// ...
}
}
```

If you have multiple builds, you can also autowire
`Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface`
and use it to get the `EntrypointLookupInterface` object for any build.
19 changes: 15 additions & 4 deletions src/Asset/EntrypointLookupCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,30 @@
*
* @final
*/
class EntrypointLookupCollection
class EntrypointLookupCollection implements EntrypointLookupCollectionInterface
{
private $buildEntrypoints;

public function __construct(ContainerInterface $buildEntrypoints)
private $defaultBuildName;

public function __construct(ContainerInterface $buildEntrypoints, string $defaultBuildName = null)
{
$this->buildEntrypoints = $buildEntrypoints;
$this->defaultBuildName = $defaultBuildName;
}

public function getEntrypointLookup(string $buildName): EntrypointLookupInterface
public function getEntrypointLookup(string $buildName = null): EntrypointLookupInterface
{
if (null === $buildName) {
if (null === $this->defaultBuildName) {
throw new UndefinedBuildException('There is no default build configured: please pass an argument to getEntrypointLookup().');
}

$buildName = $this->defaultBuildName;
}

if (!$this->buildEntrypoints->has($buildName)) {
throw new UndefinedBuildException(sprintf('Given entry point "%s" is not configured', $buildName));
throw new UndefinedBuildException(sprintf('The build "%s" is not configured', $buildName));
}

return $this->buildEntrypoints->get($buildName);
Expand Down
22 changes: 22 additions & 0 deletions src/Asset/EntrypointLookupCollectionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of the Symfony WebpackEncoreBundle package.
* (c) Fabien Potencier <[email protected]>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\WebpackEncoreBundle\Asset;

use Symfony\WebpackEncoreBundle\Exception\UndefinedBuildException;

interface EntrypointLookupCollectionInterface
{
/**
* Retrieve the EntrypointLookupInterface for the given build.
*
* @throws UndefinedBuildException If the build does not exist.
*/
public function getEntrypointLookup(string $buildName = null): EntrypointLookupInterface;
}
10 changes: 9 additions & 1 deletion src/DependencyInjection/WebpackEncoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
namespace Symfony\WebpackEncoreBundle\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookup;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;

final class WebpackEncoreExtension extends Extension
{
Expand Down Expand Up @@ -46,14 +48,20 @@ public function load(array $configs, ContainerBuilder $container)

$container->getDefinition('webpack_encore.entrypoint_lookup_collection')
->replaceArgument(0, ServiceLocatorTagPass::register($container, $factories));
$container->setAlias(EntrypointLookupInterface::class, new Alias($this->getEntrypointServiceId('_default')));
}

private function entrypointFactory(ContainerBuilder $container, string $name, string $path, bool $cacheEnabled): Reference
{
$id = sprintf('webpack_encore.entrypoint_lookup[%s]', $name);
$id = $this->getEntrypointServiceId($name);
$arguments = [$path.'/'.self::ENTRYPOINTS_FILE_NAME, $cacheEnabled ? new Reference('webpack_encore.cache') : null, $name];
$container->setDefinition($id, new Definition(EntrypointLookup::class, $arguments));

return new Reference($id);
}

private function getEntrypointServiceId(string $name): string
{
return sprintf('webpack_encore.entrypoint_lookup[%s]', $name);
}
}
2 changes: 2 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<argument /> <!-- build list of entrypoints locator -->
</service>

<service id="Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface" alias="webpack_encore.entrypoint_lookup_collection" />

<service id="webpack_encore.tag_renderer" class="Symfony\WebpackEncoreBundle\Asset\TagRenderer">
<argument type="service" id="webpack_encore.entrypoint_lookup_collection" />
<argument type="service" id="assets.packages" />
Expand Down
21 changes: 20 additions & 1 deletion tests/Asset/EntrypointLookupCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,35 @@
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollection;
use PHPUnit\Framework\TestCase;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;

class EntrypointLookupCollectionTest extends TestCase
{
/**
* @expectedException Symfony\WebpackEncoreBundle\Exception\UndefinedBuildException
* @expectedExceptionMessage Given entry point "something" is not configured
* @expectedExceptionMessage The build "something" is not configured
*/
public function testExceptionOnMissingEntry()
{
$collection = new EntrypointLookupCollection(new ServiceLocator([]));
$collection->getEntrypointLookup('something');
}

/**
* @expectedException Symfony\WebpackEncoreBundle\Exception\UndefinedBuildException
* @expectedExceptionMessage There is no default build configured: please pass an argument to getEntrypointLookup().
*/
public function testExceptionOnMissingDefaultBuildEntry()
{
$collection = new EntrypointLookupCollection(new ServiceLocator([]));
$collection->getEntrypointLookup();
}

public function testDefaultBuildIsReturned()
{
$lookup = $this->createMock(EntrypointLookupInterface::class);
$collection = new EntrypointLookupCollection(new ServiceLocator(['the_default' => function() use ($lookup) { return $lookup; }]), 'the_default');

$this->assertSame($lookup, $collection->getEntrypointLookup());
}
}
20 changes: 20 additions & 0 deletions tests/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Symfony\WebpackEncoreBundle\Tests;

use Symfony\Component\DependencyInjection\Reference;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface;
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;
use Symfony\WebpackEncoreBundle\CacheWarmer\EntrypointCacheWarmer;
use Symfony\WebpackEncoreBundle\WebpackEncoreBundle;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -96,6 +98,14 @@ public function testCacheWarmer()
// check for both build keys
$this->assertEquals(['_default' => 0, 'different_build' => 1], $data[0]);
}

public function testAutowireableInterfaces()
{
$kernel = new WebpackEncoreIntegrationTestKernel(true);
$kernel->boot();
$container = $kernel->getContainer();
$this->assertInstanceOf(WebpackEncoreAutowireTestService::class, $container->get(WebpackEncoreAutowireTestService::class));
}
}

class WebpackEncoreIntegrationTestKernel extends Kernel
Expand Down Expand Up @@ -145,6 +155,9 @@ public function registerContainerConfiguration(LoaderInterface $loader)
$container->register(WebpackEncoreCacheWarmerTester::class)
->addArgument(new Reference('webpack_encore.entrypoint_lookup.cache_warmer'))
->setPublic(true);

$container->autowire(WebpackEncoreAutowireTestService::class)
->setPublic(true);
});
}

Expand Down Expand Up @@ -173,3 +186,10 @@ public function warmCache(string $cacheDir)
$this->entrypointCacheWarmer->warmUp($cacheDir);
}
}

class WebpackEncoreAutowireTestService
{
public function __construct(EntrypointLookupInterface $entrypointLookup, EntrypointLookupCollectionInterface $entrypointLookupCollection)
{
}
}