1

I have this method to notify "my followers" which is called after a new event has been added. It works but with more than one email makes all the process very slow since the popup waits that all the emails have been sent before showing to the user that the event has been added and the spinning wheel is going forever. I can't think of any way to do it "behind the scene" after the user get the message that the event has been added.

public function notifiedFollowers($creator_id, $type, $event_id){
   $query = $this->_db->prepare("SELECT * FROM followers WHERE user_id = ?");
   $query->bindParam(1, $creator_id, PDO::PARAM_INT);
   $query->execute();


      while($row = $query->fetch(PDO::FETCH_OBJ)) {

         $creator  = new User($creator_id);
         $creatorName = $creator->data()->name;
         $user = new User($row->followers_id);
         $mail = new PHPMailer();
         $template = New MailFactory();
         $mail->IsSMTP(); 
         $mail->Host = "myHost";  
         $mail->SMTPAuth = true; 
         $mail->Username = "myUser";
         $mail->Password = "myPassword";
         $mail->IsHTML(true);    
         $mail->From = 'from email';
         $mail->FromName = 'from name';
         $mail->AddAddress($user->data()->username); 
         $mail->Subject = 'add subject here';
         $mail->Body    = $template->notifiedFollowersEmail($creatorName, $user->data()->name, $type, $event_id);
            if(!$mail->send()) {
              echo $mail->ErrorInfo;
              die();
             }
      }
}

*UPDATE******

I solved the problem using cron jobs. Please check my answer.

Mat
  • 6,236
  • 9
  • 42
  • 55

2 Answers2

3

You are looking for Threads

<?php
class AsyncEmail extends Thread {

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

    public function run() {
        /** Add your email sending code here. **/
    }
}

// and call this following lines in loop
$aEmail = new AsyncEmail( $arg );
var_dump($aEmail->start());
?>

This code will work asynchronously in the background of your code, and your user will not have to wait for any step to complete.

Have a look at this PHP threading call to a php function asynchronously

Kohjah Breese
  • 4,008
  • 6
  • 32
  • 48
zzlalani
  • 22,960
  • 16
  • 44
  • 73
  • thanks for that. Do i have to use the function `run()` or can I just copy my function inside the class? – Mat Mar 25 '14 at 07:24
  • 1
    copy the function in run and call this `$aEmail->start()` in loop – zzlalani Mar 25 '14 at 07:26
  • Sorry, Can I pass the variable inside `start($creator_id, $type, $event_id)`? – Mat Mar 25 '14 at 07:27
  • no create an array/object and sent it through the Class and set in the constructor. check the update. – zzlalani Mar 25 '14 at 07:31
  • in your case send the object `$mail` and call `$mail->send()` in run – zzlalani Mar 25 '14 at 07:32
  • sorry again but now it's not really clear what I am suppose to do. I instantiate `$mail` inside the loop so as far as I understand I should send the object multiple times. isn't slow as well? thanks for your patience ;-) – Mat Mar 25 '14 at 08:00
  • well you have to give it a try it will answer your question, – zzlalani Mar 25 '14 at 08:02
  • also you can make an object/array with all the data that is required to send email like `$creator`, `$creatorName`, `$user` and `$template->notifiedFollowersEmail($creatorName, $user->data()->name, $type, $event_id);` make an array and send it to thread class now you can make the `mailer` object in your thread and run it separately – zzlalani Mar 25 '14 at 08:09
3

I finally found a perfect solution: Cron Job

First of all I created a database where I store the "job" that has to be done

CREATE TABLE IF NOT EXISTS `cron_jobs_new_event` (
  `cron_job_id` int(32) NOT NULL AUTO_INCREMENT,
  `event_id` int(32) NOT NULL,
  `user_id` int(32) NOT NULL,
  `notify` int(32) NOT NULL,
  `executed` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`cron_job_id`),
  KEY `event_id` (`event_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- Constraints for table `cron_jobs_new_event`
--
ALTER TABLE `cron_jobs_new_event`
  ADD CONSTRAINT `cron_jobs_new_fk` FOREIGN KEY (`event_id`) REFERENCES `event` (`event_id`) ON DELETE CASCADE ON UPDATE CASCADE;

I use hostgator so I set up the cron job to run every 15 minutes: enter image description here

cron.php simply call a method from my class Notification

<?php require 'core/init.php';

$notification = new Notification();
$notification->notifiedFollowers();

and this is my method that does the magic (at least for me ;-)

     public function notifiedFollowers(){

        $query = $this->_db->prepare("SELECT user_id FROM cron_jobs_new_event WHERE executed = '0' AND notify = '1'");
        $query->execute();
        while($row = $query->fetch(PDO::FETCH_OBJ)) {
            $userCreator = $row->user_id;
                    $q = $this->_db->prepare("SELECT * FROM followers WHERE user_id = ?");
                        $q->bindParam(1, $userCreator, PDO::PARAM_INT);
                            $q->execute();

                                    while($followers = $q->fetch(PDO::FETCH_OBJ)) {

                                        $type='try';
                                        $creator  = new User($followers->user_id);
                                        $creatorName = $creator->data()->name;
                                        $userFollower = new User($followers->followers_id);
                                        $mail = new PHPMailer();
                                        $template = New MailFactory();
                                        $mail->IsSMTP(); 
                                        $mail->Host = "my host";  
                                        $mail->SMTPAuth = true; 
                                        $mail->Username = "my username";
                                        $mail->Password = "myPassword";
                                        $mail->IsHTML(true);    
                                        $mail->From = 'ev';
                                        $mail->FromName = 'Events Team';
                                        $mail->AddAddress($userFollower->data()->username); 
                                        $mail->Subject = 'Somebody add a new event!';
                                        $mail->Body    = $template->notifiedFollowersEmail($creatorName, $userFollower->data()->name, $type, $followers->event_id);

                                        if(!$mail->send()) {
                                        echo $mail->ErrorInfo;
                                        die();
                                        }
                                    }
//here I update the database so next time the cron runs, It won't send the same message
                        $update = $this->_db->prepare("UPDATE cron_jobs_new_event SET executed = '1'  WHERE cron_job_id =  ?");
                        $update->bindParam(1, $row->cron_job_id, PDO::PARAM_INT);
                        $update->execute();
            }
        }

I hope this helps somebody else

Mat
  • 6,236
  • 9
  • 42
  • 55