Email Template Dev

Usage

Definition of contexts

In your local bundles, you must create a configuration file defining the email contexts.

The location is: *Bundle/Resources/config/email-contexts.yml

The file must contain the key email-contexts as root.

Each context will have the name of its key in the context.

A context is definable with the following keys:

  • subject: The default subject of the email
  • fromAddress: The default send address
  • textBody: The default plain-text content
  • htmlBody: The default HTML content
  • data {exclamation-triangle icon} required: The list of data in the context

The data of a context (key data) is defined with the following keys:

  • tokenEntities: Associative array of available replacement tokens in the email body, variable name => type
  • loopEntities: List of available loop structures (see Quotes template operation for more info)

Context data

The data of each context is defined in an associative array allowing to expose the properties (or methods) of objects having the @Reportable annotation (ValueIn\CommonBundle\Annotation\Reportable).

For example, we need to display the username of the current user in the email : we will define the tokenEntities key in this way:

email-contexts:
    product-added-to-cart:
        data:
            tokenEntities:
                user: AppBundle\Entity\User

From the @Reportable annotation the visual editor will display an auto-completion listing the visible elements of the object in question:

You may not have the possibility to add these annotations on entities (or any kind of object) of the generic.

In this case, you simply need to set up a decorator for the object and apply the @Reportable annotation to the getters of this decorator.

Example: The entity AppBundleEntityProduct has no @Reportable annotation. We create the following decorator:

use ValueIn\CommonBundle\Annotation\Reportable;

class ProductInformation
{
    /**
     * @var Product
     */
    private $product;

    public function __construct(
        Product $product
    ) {
        $this->product = $product;
    }

    /**
     * @Reportable("Title")
     *
     * @return string
     */
    public function getTitle(): string
    {
        return $this->product->getTitle();
    }
}

When calling the email service, we will pass this decorator as a parameter so that the types of the tokenEntities are valid (see the usage example)

Example of a context

email-contexts:
    product-added-to-cart:
        subject: Your added a product to your cart
        fromAddress: no-reply@your-shop.com
        textBody: |
            Hello [[user.username]],

            You added product [[product.title]] into your cart.

            Here some detailed informations about this product :

            {% for attr in product.attributes %}
             - {{ attr.name }}: {{ attr.value }}
            {% endfor %}
        htmlBody: |
            <p>Hello [[user.username]],</p>

            <p>You added product <b>[[product.title]]</b> into your cart.</p>

            <p>Here some detailed informations about this product :</p>

            <ul>
                <li class="productAttribute">
                    <b>[[productAttribute.name]]&nbsp;:&nbsp;</b>
                    [[productAttribute.value]]
                </li>
            </ul>

        data:
            tokenEntities:
                user:             AppBundle\Entity\User
                product:          Local\EmailBundle\Model\Template\Email\ProductInformation
                productAttribute: Local\EmailBundle\Model\Template\Email\ProductAttributeInformation
            loopEntities:
                - 
                    key: productAttribute
                    from: product.attributes
                    label: Product Attribute
                    types: 
                        - li
                    color: hsl(195, 53%, 79%)

Priority of loading

Contexts are loaded in this order of priority:

  • generic contexts
  • local bundle contexts, in ascending alphabetical order by bundle name (TestBundle will be loaded before ZooBundle)
NOTE: The local bundle must implement the AppBundle\Interfaces\Switchable interface and the isEnabled method must return true for the configuration to be taken into account.

Overloading and merging of contexts

Contexts are defined in the generic application.

It is possible to overload these contexts by redefining them in your local bundles.

The overloading is done with the array_replace_recursive function.

You can also overload contexts defined in local bundles, provided that the overloading is done in the correct order of priority. (ABundle will not be able to override contexts from BBundle, but the reverse will be possible).

Debugger

From the symfony logger, it is possible to check the loading of contexts. The loading order is chronological and the final merge is displayed last.

Use of the e-mail service

The AppBundle\Service\EmailSender allows to send an email for a given context.

The method to call is sendEmailFromTemplate(string $templateName, string $to, ?string $toName, array $params = []): void

$templateName is the name of the context you defined, $to is the destination email address. The optional $toName parameter allows you to assign a name to the email address and the array $params is the array of variables that will be used in the rendering of the email body.

Example

$this->emailSender->sendEmailFromTemplate('product-added-to-cart', $user->getEmail(), $user->getUsername(), [
    'user'             => $user,
    'product'          => new ProductInformation($event->getProduct()),
    'productAttribute' => new ProductAttributeInformation,
]);