Skip to content
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

Integration with JS client #3

Merged
merged 3 commits into from
Nov 30, 2023
Merged
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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<div align="center" style="text-align: center; margin-bottom: 50px">
<h1 align="center">AMP Client PHP</h1>
<img src="docs/images/logo.png" alt="AMP Client PHP Logo" align="center" width="100">
<h1>AMP Client PHP</h1>
<p>:mega: PHP Client for Advertising Management Platform</p>
</div>

Expand All @@ -19,10 +20,9 @@ $ composer require 68publishers/amp-client

## Versions compatibility matrix

| PHP client version | PHP version | AMP version | API version |
|:----------------------:|-------------|:----------------:|:-----------:|
| `^1.0` | `>=7.4` | `>=2.12` | `1` |

| PHP client version | PHP version | AMP version | API version |
|:------------------:|-------------|:----------------:|:-----------:|
| `>=1.0` | `>=7.4` | `>=2.12` | `1` |

## Integration without a framework

Expand Down
Binary file added docs/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 38 additions & 5 deletions docs/integration-with-nette-framework.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Integration with Nette framework
<div align="center" style="text-align: center; margin-bottom: 50px">
<img src="images/logo.png" alt="AMP Client PHP Logo" align="center" width="100">
<h1>AMP Client PHP</h1>
<h2 align="center">Integration with Nette framework</h2>
</div>

For more information on how the client works, we also recommend reading the [Integration without a framework](./integration-without-framework.md) section.

* [Client integration](#client-integration)
* [Latte macros integration](#latte-macros-integration)
* [Using multiple rendering modes](#using-multiple-rendering-modes)
* [Configuring client before the first fetch](#configuring-client-before-the-first-fetch)
* [Renaming the macro](#renaming-the-macro)

Expand Down Expand Up @@ -64,6 +69,7 @@ amp_client:
random: %appDir%/templates/amp/random.latte
multiple: %appDir%/templates/amp/multiple.latte
not_found: %appDir%/templates/amp/not_found.latte
client_side: %appDir%/templates/amp/client_side.latte
```

Two important services are now available in the DI Container - `AmpClientInterface` and `RendererInterface`.
Expand Down Expand Up @@ -100,23 +106,24 @@ final class MyPresenter extends Presenter {

## Latte macros integration

Banners can be rendered directly from the Latte template without having to manually call the client. We need to register another extension for this:
Banners can be rendered directly from the Latte template without having to manually call the client. Another extension must be registered for this:

```neon
extensions:
amp_client.latte: SixtyEightPublishers\AmpClient\Bridge\Nette\DI\AmpClientLatteExtension(%debugMode%)
```

Now we have the macro `{banner}` available in the application, and we can use it in templates:
Now the macro `{banner}` is available in the application and can be used in templates:

```latte
{banner homepage.top}
{banner homepage.promo, ['role' => 'guest']}
{banner homepage.promo, resources: ['role' => 'guest']}
{banner homepage.bottom, attributes: ['class' => 'my-awesome-class']}
```

Banners are now requested via API and rendered to the template automatically.

Each `{banner}` macro makes a separate request to the AMP API, so in our example above, two requests are sent.
Each `{banner}` macro makes a separate request to the AMP API, so in our example above, three requests are sent.
This can be solved by the following configuration:

```neon
Expand All @@ -127,6 +134,32 @@ amp_client.latte:
Now when rendering a page via `nette/application`, information about all banners to be rendered is collected and a request to the AMP API is sent only once the whole template is rendered.
The banners are then inserted back into the rendered page. This behavior also works automatically with AJAX snippets.

The following rendering modes are available:

- **direct** ([DirectRenderingMode](../src/Bridge/Latte/RenderingMode/DirectRenderingMode.php)) - The default mode, API is requested separately for each banner.
- **client_side** ([ClientSideRenderingMode](../src/Bridge/Latte/RenderingMode/ClientSideRenderingMode.php)) - Renders only a wrapper element and leaves loading banners on the JavaScript client. Banners are loaded by calling the `attachBanners()` function.
- **queued_in_presenter_context** ([QueuedRenderingInPresenterContextMode](../src/Bridge/Latte/RenderingMode/QueuedRenderingInPresenterContextMode.php)) - Renders only HTML comments as placeholders and stores requested positions in a queue. It will request, render and place all banners to them positions at once before the presenter returns a response.
- **queued** ([QueuedRenderingMode](../src/Bridge/Latte/RenderingMode/QueuedRenderingMode.php)) - Same behavior as `queued_in_presenter_context`, but it doesn't take into account whether the website template is currently being rendered through the Nette application. It is more suited for an integration without a framework.

### Using multiple rendering modes

Besides the default rendering mode, which is set by the option `rendering_mode`, it is possible to configure alternative modes that can be used in templates.

```neon
amp_client.latte:
rendering_mode: queued_in_presenter_context # the default value is "direct"
alternative_rendering_modes:
- client_side
```

```latte
{* The first banner will be rendered with the default mode *}
{banner homepage.top}

{* The second banner will be rendered client side *}
{banner homepage.promo, mode: 'client_side'}
```

### Configuring client before the first fetch

Occasionally, we may want to configure the client before making a request to the AMP API from the template.
Expand Down
108 changes: 97 additions & 11 deletions docs/integration-without-framework.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# Integration without a framework
<div align="center" style="text-align: center; margin-bottom: 50px">
<img src="images/logo.png" alt="AMP Client PHP Logo" align="center" width="100">
<h1>AMP Client PHP</h1>
<h2 align="center">Integration without a framework</h2>
</div>

* [Client initialization](#client-initialization)
* [Cache](#cache)
* [Custom Guzzle options](#custom-guzzle-options)
* [Fetching banners](#fetching-banners)
* [Rendering banners](#rendering-banners)
* [Rendering banners on the client side](#rendering-banners-on-the-client-side)
* [Templates overwriting](#templates-overwriting)
* [Rendering banners using Latte](#rendering-banners-using-latte)
* [Latte templating system integration](#latte-templating-system-integration)
* [Using multiple rendering modes](#using-multiple-rendering-modes)
* [Renaming the macro](#renaming-the-macro)

## Client initialization

Expand Down Expand Up @@ -143,7 +152,6 @@ $homepagePromo = $response->getPosition('homepage.promo');
Banners can be rendered simply by using the `Renderer` class:

```php
use SixtyEightPublishers\AmpClient\AmpClientInterface;
use SixtyEightPublishers\AmpClient\Renderer\Renderer;
use SixtyEightPublishers\AmpClient\Response\BannersResponse;

Expand All @@ -154,6 +162,30 @@ $renderer = Renderer::create();
echo $renderer->render($response->getPosition('homepage.top'));
```

The second argument can be used to pass an array of attributes to be contained in the banner's HTML wrapper element.

```php
echo $renderer->render($response->getPosition('homepage.top', ['class' => 'my-awesome-class']));
```

### Rendering banners on the client side

Banner rendering can be left to the [JavaScript client](https://github.com/68publishers/amp-client-js) using the `Renderer::renderClientSide()` method.

```php
use SixtyEightPublishers\AmpClient\Renderer\Renderer;
use SixtyEightPublishers\AmpClient\Request\ValueObject\Position;

$renderer = Renderer::create();

echo $renderer->renderClientSide(new Position('homepage.top'));
echo $renderer->renderClientSide(new Position('homepage.promo'), ['class' => 'my-awesome-class']);
```

Banners rendered in this way will be loaded by the JavaScript client when its `attachBanners()` function is called.

### Templates overwriting

The default templates are written as `.phtml` templates and can be found [here](../src/Renderer/Phtml/Templates). Templates can be also overwritten:

```php
Expand All @@ -163,7 +195,7 @@ use SixtyEightPublishers\AmpClient\Renderer\Templates;

$bridge = new PhtmlRendererBridge();
$bridge = $bridge->overrideTemplates(new Templates([
Templates::TemplateSingle => '/my_custom_template_for_single_position.phtml',
Templates::Single => '/my_custom_template_for_single_position.phtml',
]));

$renderer = Renderer::create($bridge);
Expand All @@ -175,10 +207,11 @@ The following template types can be overwritten:
use SixtyEightPublishers\AmpClient\Renderer\Templates;

new Templates([
Templates::TemplateSingle => '/single.phtml', # for positions with the display type "single"
Templates::TemplateMultiple => '/multiple.phtml', # for positions with the display type "multiple"
Templates::TemplateRandom => '/random.phtml', # for positions with the display type "random"
Templates::TemplateNotFound => '/notFound.phtml', # for positions that were not found
Templates::Single => '/single.phtml', # for positions with the display type "single"
Templates::Multiple => '/multiple.phtml', # for positions with the display type "multiple"
Templates::Random => '/random.phtml', # for positions with the display type "random"
Templates::NotFound => '/notFound.phtml', # for positions that were not found
Templates::ClientSide => '/clientSide.phtml',
])
```

Expand Down Expand Up @@ -244,13 +277,14 @@ $engine->render(__DIR__ . '/template.latte');
{* ./template.latte *}

{banner homepage.top}
{banner homepage.promo, ['role' => 'guest']}
{banner homepage.promo, resources: ['role' => 'guest']}
{banner homepage.bottom, attributes: ['class' => 'my-awesome-class']}
```

Banners are now requested via API and rendered to the template automatically.

Each `{banner}` macro makes a separate request to the AMP API, so in our example above, two requests are sent.
This can be solved, however you need to render the Latte to a text string, not a buffer.
By default, each `{banner}` macro makes a separate request to the AMP API, so in our example above, three requests are sent.
This can be solved, however you need to render the Latte to a string, not a buffer.

```php
use SixtyEightPublishers\AmpClient\AmpClientInterface;
Expand All @@ -265,7 +299,7 @@ use Latte\Engine;

$engine = new Engine();
$provider = (new RendererProvider($client,$renderer))
->setDebugMode(true) # exceptions from Client and Renderer are suppressed in non-debug mode
->setDebugMode(true)
->setRenderingMode(new QueuedRenderingMode());

AmpClientLatteExtension::register($engine, $provider);
Expand All @@ -276,3 +310,55 @@ echo $provider->renderQueuedPositions($output);
```

Now the client requests both banners in the template with one request.

The following rendering modes are available:

- **direct** ([DirectRenderingMode](../src/Bridge/Latte/RenderingMode/DirectRenderingMode.php)) - The default mode, API is requested separately for each banner.
- **client_side** ([ClientSideRenderingMode](../src/Bridge/Latte/RenderingMode/ClientSideRenderingMode.php)) - Renders only a wrapper element and leaves loading banners on the JavaScript client. Banners are loaded by calling the `attachBanners()` function.
- **queued** ([QueuedRenderingMode](../src/Bridge/Latte/RenderingMode/QueuedRenderingMode.php)) - Renders only HTML comments as placeholders and stores requested positions in a queue. It will request and render all banners at once when the `RendererProvider::renderQueuedPositions()` method is called.
- **queued_in_presenter_context** ([QueuedRenderingInPresenterContextMode](../src/Bridge/Latte/RenderingMode/QueuedRenderingInPresenterContextMode.php)) - Same behavior as `queued` but in the context of a Presenter only. Usable with Nette applications only.

### Using multiple rendering modes

Besides the default rendering mode, which is set by the method `RendererProvider::setRenderingMode()`, it is possible to configure alternative modes that can be used in templates.

```php
use SixtyEightPublishers\AmpClient\Bridge\Latte\RendererProvider;
use SixtyEightPublishers\AmpClient\Bridge\Latte\RenderingMode\DirectRenderingMode;
use SixtyEightPublishers\AmpClient\Bridge\Latte\RenderingMode\ClientSideRenderingMode;

/** @var AmpClientInterface $client */
/** @var RendererInterface $renderer */

$provider = new RendererProvider($client, $renderer);

$provider->setRenderingMode(new DirectRenderingMode()); # No need to actually set it up, this mode is the default.
$provider->setAlternativeRenderingModes([
new ClientSideRenderingMode(),
]);
```

```latte
{* The first banner will be rendered with the default mode (directly) *}
{banner homepage.top}

{* The second banner will be rendered client side *}
{banner homepage.promo, mode: 'client_side'}
```

### Renaming the macro

Macro `{banner}` can be renamed. This can be done by specifying the third argument of the method `AmpClientLatteExtension::register()`.

```php
use SixtyEightPublishers\AmpClient\Bridge\Latte\AmpClientLatteExtension;
use SixtyEightPublishers\AmpClient\Bridge\Latte\RendererProvider;
use Latte\Engine;

/** @var RendererProvider $provider */
/** @var Engine $engine */

AmpClientLatteExtension::register($engine, $provider, 'ampBanner');
```

The macro will now be named `{ampBanner}`.
2 changes: 1 addition & 1 deletion src/Bridge/Latte/AmpClientLatte2Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ public function macroBanner(MacroNode $node, PhpWriter $writer): string

return $writer
->using($node)
->write('echo ($this->global->ampClientRenderer)($this->global, %node.word, %node.args?);');
->write('echo ($this->global->ampClientRenderer)($this->global, %node.word, %node.array?);');
}
}
13 changes: 7 additions & 6 deletions src/Bridge/Latte/Node/BannerNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Generator;
use Latte\CompileException;
use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
use Latte\Compiler\Nodes\Php\ExpressionNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
Expand All @@ -18,7 +19,7 @@ final class BannerNode extends StatementNode
{
public ExpressionNode $positionCode;

public ?ExpressionNode $resources = null;
public ?ArrayNode $options = null;

/**
* @throws CompileException
Expand All @@ -30,19 +31,19 @@ public static function create(Tag $tag): self
$node->positionCode = $tag->parser->parseUnquotedStringOrExpression();

if ($tag->parser->stream->tryConsume(',')) {
$node->resources = $tag->parser->parseExpression();
$node->options = $tag->parser->parseArguments();
}

return $node;
}

public function print(PrintContext $context): string
{
if (null !== $this->resources) {
if (null !== $this->options) {
return $context->format(
'echo ($this->global->ampClientRenderer)($this->global, %node, %node?);',
$this->positionCode,
$this->resources,
$this->options,
);
}

Expand All @@ -56,8 +57,8 @@ public function &getIterator(): Generator
{
yield $this->positionCode;

if (null !== $this->resources) {
yield $this->resources;
if (null !== $this->options) {
yield $this->options;
}
}
}
Loading