Chapters
31 Chapters
|
3:19:40
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3
Subscribe to download the code!Compatible PHP versions: ^7.1.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
18.
Organizing Emails Logic into a Service
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
This tutorial is built on Symfony 4.3, but will work well with Symfony 4.4 or 5.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"aws/aws-sdk-php": "^3.87", // 3.110.11
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.10.1
"doctrine/doctrine-bundle": "^1.6.10", // 1.11.2
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // v2.0.0
"doctrine/orm": "^2.5.11", // v2.7.2
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.1
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-snappy-bundle": "^1.6", // v1.6.0
"knplabs/knp-time-bundle": "^1.8", // v1.9.1
"league/flysystem-aws-s3-v3": "^1.0", // 1.0.23
"league/flysystem-cached-adapter": "^1.0", // 1.0.9
"league/html-to-markdown": "^4.8", // 4.8.2
"liip/imagine-bundle": "^2.1", // 2.1.0
"nexylan/slack-bundle": "^2.1,<2.2.0", // v2.1.0
"oneup/flysystem-bundle": "^3.0", // 3.1.0
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"phpdocumentor/reflection-docblock": "^3.0|^4.0", // 4.3.1
"sensio/framework-extra-bundle": "^5.1", // v5.4.1
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.3.4
"symfony/console": "^4.0", // v4.3.4
"symfony/flex": "^1.9", // v1.21.6
"symfony/form": "^4.0", // v4.3.4
"symfony/framework-bundle": "^4.0", // v4.3.4
"symfony/mailer": "4.3.*", // v4.3.4
"symfony/messenger": "4.3.*", // v4.3.4
"symfony/property-access": "4.3.*", // v4.3.4
"symfony/property-info": "4.3.*", // v4.3.4
"symfony/security-bundle": "^4.0", // v4.3.4
"symfony/sendgrid-mailer": "4.3.*", // v4.3.4
"symfony/serializer": "4.3.*", // v4.3.4
"symfony/twig-bundle": "^4.0", // v4.3.4
"symfony/validator": "^4.0", // v4.3.4
"symfony/web-server-bundle": "^4.0", // v4.3.4
"symfony/webpack-encore-bundle": "^1.4", // v1.6.2
"symfony/yaml": "^4.0", // v4.3.4
"twig/cssinliner-extra": "^2.12", // v2.12.0
"twig/extensions": "^1.5", // v1.5.4
"twig/extra-bundle": "^2.12|^3.0", // v2.12.1
"twig/inky-extra": "^2.12", // v2.12.0
"twig/twig": "^2.12|^3.0" // v2.13.1
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.2.2
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/browser-kit": "4.3.*", // v4.3.5
"symfony/debug-bundle": "^3.3|^4.0", // v4.3.4
"symfony/dotenv": "^4.0", // v4.3.4
"symfony/maker-bundle": "^1.0", // v1.13.0
"symfony/monolog-bundle": "^3.0", // v3.4.0
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.3.4
"symfony/stopwatch": "4.3.*", // v4.3.4
"symfony/var-dumper": "^3.3|^4.0", // v4.3.4
"symfony/web-profiler-bundle": "4.3.*" // v4.3.4
}
}
8 Comments
Hello ! In case we have a .pdf file already ready in our assets, and which has been copied to the
public/build/files/manuel_utilisateur.pdf(and is therefore versioned) with Webpack Encore, how can I attach this file to send it?I know how to attach a file that is directly in the assets. Like this
But if the file is versioned, in the public folder, what can I do?
Besides, is it a good solution to attach a file from the public folder, or is it better to leave it in the assets?
This is a user manual that will be sent to each new user
Hey Kiuega
You'll need to get the
Symfony\Component\Asset\Packagesservice and callgetUrl()on it, passing the path to your build, final asset (ignoring that's versioned), e.g.$packages->getUrl('build/files/manuel.pdf')Cheers!
Hello guys,
How would you go about implementing "email notification preferences" ? I'de like users to be able to opt-in/out of different email categories (each user's preference is stored in a line in a DB table and each column is a different email category :
| user_id (int) | category_email_one (bool) | category_email_two (bool) | ... |I would like to centralize this in the service or in a messenger middleware but I cannot get my head around which is best. So there are actually two questions here :
1 - With your system, could/should I categorize emails using multiple services ? (or should i simply define a <i>category</i> in the <i>context </i>of the TemplatedEmail and create a method call checkPrefEmailAndSend in which i check the category and user preferences and then call
$this->mailer->send()?)2 - How can I check for every user's mail preferences before sending the email to messenger and if the category is set to "false" for a user, then no email is sent.
I'm in a blur on what to do and how to do it efficiently... :/
Thanks in advance for your help !
Thibault
Hey Thibault V.
That's a good question and this is how I would do it
I would create 2 entities. User and EmailCategory
A User would have a ManyToOne relationship to EmailCategory, so a User can subscribe to many categories
Then, depending on the situation, I would create an interface or a command where I can specify which categories I want to send my email. Then, I would create a query that fetches all the users that are related to any of the categories I specified, and from this point, you already know the rest, you only have to create the email body and send it
I hope it helps. Cheers!
FYI: I currently decided to do the following
1 - Define a parent Mailer service with
send()method which includes $category private param (with default value) and a verification for the category with user settings inside it.2 - Define a child Service that extends Mailer for every group of emails. Example :
<br />Account updates emails => AccountUpdatesMailer extends Mailer<br />Blog emails => BlogMailer extends Mailer<br />Security emails => SecurityMailer extends Mailer<br />...<br />3 - Each child service defines $this->category to the corresponding group (for my example:
account_updates,blog...)What's your opinion on this organization with services ?
thanks in advance for your opinion
Hey Thibault V.!
Sorry for never replying on this! For some reason, your comment got marked as SPAM and we missed it! In general, I like your solution. There is no need to hook into Messenger or Mailer in some fancy way. Instead, your solution simply creates 3 new services: each which contains the special logic you need, and then calls the normal Mailer. We do this kind of thing all the time.
The one modification I would make is this: instead of extending Mailer, I would make your classes extend nothing and instead, accept Mailer as an argument to your constructor. The only difference would be that instead of calling
parent::send(), you would eventually call$this->mailer->send().The reason for this is just that having a separate class (that doesn't extend Mailer) keeps things cleaner and simpler. You don't need to worry about the parent Mailer constructor or even using service decoration: your BlogMailer would be a normal service that automatically autowires the mailer service thanks to the MailerInterface type-hint in your constructor. This is also an example of "composition over inheritance" if you want to get really nerdy about it ;). What you would be doing is called object composition.
Cheers!
You might want to add to the Mailer service following the line
$this->mailer->send($email);the linereturn $email;. This can make the test of the service in the following chapter successful.Hey geoB,
Yep, we will do it later in this course. The final code from this course do have "return $email" line, I just double-checked :)
Cheers!
"Houston: no signs of life"
Start the conversation!