I'm working on a Symfony 3 website and I need to call a URL of my website with a cron job.
My website is hosted on OVH where I can configure my cron job.
For now, I have setup the command : ./demo/Becowo/batch/emailNewUser.php
emailNewUser.php content :
<?php
header("Location: https://demo.becowo.com/email/newusers");
?>
In the log I have :
[2017-03-07 08:08:04] ## OVH ## END - 2017-03-07 08:08:04.448008 exitcode: 0
[2017-03-07 09:08:03] ## OVH ## START - 2017-03-07 09:08:03.988105 executing: /usr/local/php5.6/bin/php /homez.2332/coworkinwq/./demo/Becowo/batch/emailNewUser.php
But emails are not sent.
How should I configure my cron job to execute this URL ?
Or should I call directly my controller ? How ?
ok, finally it works !!!
Here are the step I followed for others :
1/ You need a controller to send emails :
As the controller will be called via command, you need to injec some services
em : entity manager to flush data
mailer : to access swiftMailer service to send the email
templating : to access TWIG service to use template in the email body
MemberController.php
<?php
namespace Becowo\MemberBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Becowo\CoreBundle\Form\Type\ContactType;
use Becowo\CoreBundle\Entity\Contact;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
class MemberController extends Controller
{
private $em = null;
private $mailer = null;
private $templating = null;
private $appMember = null;
public function __construct(EntityManager $em, $mailer, EngineInterface $templating, $appMember)
{
$this->em = $em;
$this->mailer = $mailer;
$this->templating = $templating;
$this->appMember = $appMember;
}
public function sendEmailToNewUsersAction()
{
// To call this method, use the command declared in Becowo\CronBundle\Command\EmailNewUserCommand
// php bin/console app:send-email-new-users
$members = $this->appMember->getMembersHasNotReceivedMailNewUser();
$nbMembers = 0;
$nbEmails = 0;
$listEmails = "";
foreach ($members as $member) {
$nbMembers++;
if($member->getEmail() !== null)
{
$message = \Swift_Message::newInstance()
->setSubject("Hello")
->setFrom(array('toto@xxx.com' => 'Contact Becowo'))
->setTo($member->getEmail())
->setContentType("text/html")
->setBody(
$this->templating->render(
'CommonViews/Mail/NewMember.html.twig',
array('member' => $member)
))
;
$this->mailer->send($message);
$nbEmails++;
$listEmails = $listEmails . "\n" . $member->getEmail() ;
$member->setHasReceivedEmailNewUser(true);
$this->em->persist($member);
}
}
$this->em->flush();
$result = " Nombre de nouveaux membres : " . $nbMembers . "\n Nombre d'emails envoyes : " . $nbEmails . "\n Liste des emails : " . $listEmails ;
return $result;
}
}
2/ Call you controller as a service
app/config/services.yml
app.member.sendEmailNewUsers :
class: Becowo\MemberBundle\Controller\MemberController
arguments: ['@doctrine.orm.entity_manager', '@mailer', '@templating', '@app.member']
3/ Create a console command to call your controller
Doc : http://symfony.com/doc/current/console.html
YourBundle/Command/EmailNewUserCommand.php
<?php
namespace Becowo\CronBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
class EmailNewUserCommand extends ContainerAwareCommand
{
protected function configure()
{
// the name of the command (the part after "php bin/console")
$this->setName('app:send-email-new-users')
->setDescription('Send welcome emails to new users')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
// outputs a message to the console followed by a "\n"
$output->writeln('Debut de la commande d\'envoi d\'emails');
// access the container using getContainer()
$memberService = $this->getContainer()->get('app.member.sendEmailNewUsers');
$results = $memberService->sendEmailToNewUsersAction();
$output->writeln($results);
}
}
4/ Test your command !
In the console, call you command : php bin/console app:send-email-new-users
5/ Create a script to run the command
Doc (french) : http://www.christophe-meneses.fr/article/deployer-son-projet-symfony-sur-un-hebergement-perso-ovh
..Web/Batch/EmailNewUsers.sh
#!/bin/bash
today=$(date +"%Y-%m-%d-%H")
/usr/local/php5.6/bin/php /homez.1111/coworkinwq/./demo/toto/bin/console app:send-email-new-users --env=demo > /homez.1111/coworkinwq/./demo/toto/var/logs/Cron/emailNewUsers-$today.txt
Here it took me some time to get the correct script.
Take care of php5.6 : it has to match your PHP version on OVH
Don't forget to upload bin/console file on the server
homez.xxxx/name has to match with your config (I found mine on OVH, and then in the logs)
IMPORTANT : when you upload the file on the server, add execute right (CHMOD 704)
6/ Create the cron job in OVH
Call your script with the command : ./demo/Becowo/web/Batch/EmailNewUsers.sh
Language : other
7/ Wait !
You need to wait for the next run. Then have a look on OVH cron logs, or on your own logs created via the command in the .sh file
It took me several days to get it..
Enjoy !!
As commented above, you should do it with a symfony commaad. This is an example for you.
NOTE: Although it is working, you can always improve this example. Especially the way command calls your endpoint.
Controller service definition:
services:
yow_application.controller.default:
class: yow\ApplicationBundle\Controller\DefaultController
Controller itself
namespace yow\ApplicationBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
/**
* @Route("", service="yow_application.controller.default")
*/
class DefaultController
{
/**
* @Method({"GET"})
* @Route("/plain", name="plain_response")
*
* @return Response
*/
public function plainResponseAction()
{
return new Response('This is a plain response!');
}
}
Command service definition
services:
yow_application.command.email_users:
class: yow\ApplicationBundle\Command\EmailUsersCommand
arguments:
- '@http_kernel'
tags:
- { name: console.command }
Command itself
namespace yow\ApplicationBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class EmailUsersCommand extends Command
{
private $httpKernel;
public function __construct(HttpKernelInterface $httpKernel)
{
parent::__construct();
$this->httpKernel = $httpKernel;
}
protected function configure()
{
$this->setName('email:users')->setDescription('Emails users');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$request = new Request();
$attributes = [
'_controller' => 'yow_application.controller.default:plainResponseAction',
'request' => $request
];
$subRequest = $request->duplicate([], null, $attributes);
$response = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
$output->writeln($response);
}
}
Test
$ php bin/console email:users
Cache-Control: no-cache, private
X-Debug-Token: 99d025
X-Debug-Token-Link: /_profiler/99d025
This is a plain response!
1.0
200
OK