Sending emails is a very common task in modern Enterprise Software Applications. If your application is built on top of PHP Symfony Framework, just follow these simple steps:

Prerequisites:

Step 1. Make sure you have the Symfony mailer component by doing:

composer require symfony/mailer

 Step 2. Configure your mailer in the config/packages/mailer.yaml file:

# config/packages/mailer.yaml

framework:
    mailer:
        dsn: '%env(MAILER_DSN)%'

 Notice that MAILER_DSN is the connection string to the mailing transport. For more information on this refer to  Symfony Mailer Component

 Step 3. Inject the Symfony\Component\Mailer\MailerInterface in the Controller or Service Class from where you are going to send emails and implement something like this:

use App\ApiBundle\Exceptions\SystemException;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Email;
use Twig\Environment;

class MailService
{
    /**
     * @var MailerInterface
     */
    private MailerInterface $mailer;
    
    /**
     * @var Environment
     */
    private Environment $twig;
    
    /**
     * @param MailerInterface $mailer
     * @param Environment $twig
     */
    public function __construct(MailerInterface $mailer, Environment $twig)
    {
        $this->mailer = $mailer;
        $this->twig = $twig;
    }
    
    /**
     * @param SomeDtoClass $forThis
     * @return array
     */
    public function getEmailPayload(SomeDtoClass $forThis): array
    {
        //...Get Email Twig Template Name
        $payload['twigTemplateName'] = $forThis->templateName;
        //...Get  Data to put in Html Text
        $payload['HtmlBody'] = $this->getHtmlBody($forThis->data);
        //...Get Text To put in no Html format Email
        $payload['rawTextBody'] = $this->getRawTextBody($forThis->data);
        //...Get Sender
        $payload['sender'] = $this->getEmailSenser($forThis);
        //...Get Recipient(s) email address
        $payload['sendTo'] = $this->getSendTo($forThis->user);
        //...Get Email Subject Text string
        $payload['subject'] = $this->getEmailSubject($forThis);
        //...Get Email Attachments if any
        $payload['attachments'] = $this->getEmailAttachments($forThis->attachments);
        
        return $payload;
    }
    
    /**
     * @param array $payload
     * @return bool
     */
    public function sendEmail(array $payload): bool
    {
        try {
            //Use this in case you prefer to have all sensitive data stored somewhere else like in a Schema table no accesible by anyone but the sys admin
            $dsn = $this->getParamFromDb('MAILER_DSN');
            $transport = Transport::fromDsn($dsn);
            $mailer = new Mailer($transport);
            $message = new Email();
            
            $message->getHeaders()
                // this non-standard header tells compliant autoresponders ("email holiday mode") to not
                // reply to this message because it's an automated email
                ->addTextHeader('X-Auto-Response-Suppress', 'OOF, DR, RN, NRN, AutoReply');
            
            $message->from($payload['sender'])
                ->to($payload['sendTo'])
                ->subject($payload['subject'])
                ->text($this->twig->render('emails/' . $payload['twigTemplateName'] . '.txt.twig', $payload['rawTextBody']))
                ->html($this->twig->render('emails/' . $payload['twigTemplateName'] . '.html.twig', $payload['HtmlBody']));
            //Most Email services like Google and Yahoo accept up to 10 attachments and total size up to 20 MB
            foreach ($payload['attachments'] as $attachment) {
                $message->attach($attachment, $attachment->name, $attachment->contentType);
            }
            //Send Email
            $mailer->send($message);
            
        } catch (\Throwable $e) {
            throw new SystemException($e->getMessage());
        }
        
        return true;
    }
    
}

 It is always a good idea to use Twig Templates for the email content. This way, you can have very nice formatted text and a template that can be reused over and over again.

Refer to Symfony Documentation for more details and more options.

 

 

 

 

 

 

In PHP, autowiring refers to a technique for automatically resolving dependencies when instantiating classes. To implement autowiring in PHP, you can use a dependency injection container, such as PHP-DI package, which provides autowiring out of the box.

Prerequisites:

 

Step 1. Install PHP-DI via composer:

composer require php-di/php-di

Step 2. Create a container instance and configure it to use autowiring:

use DI\ContainerBuilder;

$containerBuilder = new ContainerBuilder();
$containerBuilder->useAutowiring(true);
$container = $containerBuilder->build();

Step 3. Define your class and its dependencies:

class Foo {
  public function __construct(Bar $bar) {
    // ...
  }
}

class Bar {
  // ...
}

Step 4. Resolve the class using the container:

$foo = $container->get(Foo::class);

The container will automatically instantiate the Bar dependency and pass it to the constructor of Foo.

Autowiring can be limited to a specific namespace or package by using the useAnnotations(false) method of the container builder and annotating the classes with @Inject or @Autowired annotations. Additionally, it's important to note that autowiring can only work with classes that have type-hinted dependencies.

If you want to implement autowiring without any package: How to implement autowiring in php using reflexion class

 

 

 

Autowiring in PHP refers to the ability to automatically resolve dependencies of a class without the need for manual instantiation or injection of dependencies.To implement autowiring in PHP using the ReflectionClass, you can follow these steps:

Step 1. Define the class that has dependencies that need to be autowired:

class MyTestingClass
{
    /**
     * @var DependencyClass 
     */
    private DependencyClass $dependency;
    
    /**
     * @param DependencyClass $dependency
     */
    public function __construct(DependencyClass $dependency)
    {
        $this->dependency = $dependency;
    }
}

Step 2. Create a method that uses ReflectionClass to get the constructor of the class and resolve its dependencies:

/**
 * @throws ReflectionException
 */
function resolveDependencies($className)
{
    $reflection = new ReflectionClass($className);
    $constructor = $reflection->getConstructor();
    $dependencies = [];
    
    if ($constructor) {
        foreach ($constructor->getParameters() as $param) {
            $dependency = $param->getClass();
            if ($dependency) {
                //Use recursion to autowire nested dependencies
                $dependencies[] = resolveDependencies($dependency->getName());
            }
        }
    }
    
    return $reflection->newInstanceArgs($dependencies);
}

Step 3. Call the resolveDependencies() function with the name of the class that needs autowiring:

$instance = resolveDependencies('MyTestingClass');

This will create an instance of ExampleClass with its dependency automatically resolved using autowiring. This approach assumes that all dependencies can be instantiated using their default constructor. If any of the dependencies require additional arguments to be passed to their constructor, you will need to modify the resolveDependencies() function accordingly.

ReflectionClass is very powerful tool and it can help you not only to autowire dependencies, but for validating data in a very easy way.

For more on this look into these posts:

How to validate input data in Symfony using DTOs

Using DTOs in PHP Symfony

 

 

 

 

Most modern Enterprise Systems require to generate reports, agreements, business plans or a variety of documents that can be downloaded in PDF format. Pdf is one of the most popular file formats used for document sharing as it has a small file size, can be viewed and edited on a computer and also it can be printed with great quality. Follow these steps to prepare your Symfony project for Pdf generation:

Prerequisites

 

Step 1. Install wkhtmltopdf1 package in your server:

### This is the suggested installation procedure in CentOS 7
$> cd /tmp
### Get most recent package
$> wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.centos7.x86_64.rpm
### Install it along with dependencies
$> sudo yum -y localinstall wkhtmltox-0.12.6-1.centos7.x86_64.rpm

 Step 2. Install Symfony package2

$> cd /var/www/symfony-root
$> composer require mikehaertl/phpwkhtmltopdf

 Step 3. Create a new action method in your Symfony Controller to download the pdf:

public function getCdpPdfForLineItemId($lineItemId, CdpService $cdpService): Response
    {
        $cdpData = $cdpService->getCdpData($lineItemId);//Gather all data
        $htmlPages = $cdpService->getHtmlPages($cdpData);//Get html pages with this data
        $pdf = $cdpService->getPdf($htmlPages);//Generate Pdf
        if (!$pdf->send()) {
            throw new PdfDownloadException($pdf->getError());
        } else {
            return new Response('ok');
        }
    }

 Step 4. In this example $cdpData variable is an array that will be passed to the getHtmlPages method in this way:

    public function getHtmlPages(array $cdpData): array
    {
        try {
            $cdpData['images'] = $this->getEncodedImages($cdpData);
            $htmlPages = [];
            $htmlPages['cover'] = $this->getHtmlForTemplate(self::TITLE_PAGE_TEMPLATE, $cdpData);
            $cdpData['pageNumber'] = 3;
            $htmlPages['pages'][] = $this->getHtmlForTemplate(self::OVERVIEW_PAGE_TEMPLATE, $cdpData);
            $cdpData['pageNumber'] += 1;

            ...




### Each page is using a twig template that is rendered this way
    public function getHtmlForTemplate(string $templateName, array $cdpData = []): string
    {
        try {
            return $this->twig->render(self::CDP_TEMPLATE_DIR . $templateName, $cdpData);
        } catch (Throwable $e) {
            throw new SystemException('Template Rendering failed');
        }
    }

In each Twig file you will use the $cdpData keys that corresponds to the twig template variables defined

Step 5. In this example once we get the $htmlPages we use the getPdf method to generate the Pdf Document:

    /**
     * @param array $htmlPages
     * @return Pdf
     * @throws LoaderError
     * @throws RuntimeError
     * @throws SyntaxError
     */
    public function getPdf(array $htmlPages): Pdf
    {
        try {
            $pdf = new Pdf(array(
                'no-outline',         // Make Chrome not complain
                'margin-top' => '0',
                'margin-left' => '0',
                'margin-right' => '0',
                'margin-bottom' => '0',
                'ignoreWarnings' => true,
                'footer-spacing' => '0',
                'no-outline',
                'commandOptions' => [
                    'useExec' => true,
                    'procEnv' => [
                        'LANG' => 'en_US.utf-8',
                    ],
                    'escapeArgs' => false,
                    'procOptions' => [
                        'bypass_shell' => true,
                        'suppress_errors' => true,
                    ],
                ],
                // Default page options
                'disable-smart-shrinking',
                //'user-style-sheet' => '/path/to/pdf.css',
            ));
            //Add cover
            $pdf->addCover($htmlPages['cover']);
            //Create Table of Contents
            $pdf->addToc(['xsl-style-sheet' => $this->getHtmlForTemplate('pageHeaderGeneric.html.twig')]);
            //Add Pages to Pdf
            foreach ($htmlPages['pages'] as $htmlPage) {
                $pdf->addPage($htmlPage, null, 'html');
            }

            return $pdf;
        } catch (Throwable $e) {
            throw new SystemException('Template Rendering failed');
        }
    }

With this code, the Pdf will also have a nice Cover Page and a Table of Contents Page along with all other required pages.

 

 

1 Refer to wkhtmltopdf website for more downloads

2 Refer to the packagist website for more information