├── .gitignore ├── Config └── Schema │ ├── empty │ ├── schema.mwb │ └── schema.sql ├── Console └── Command │ └── Task │ └── empty ├── Controller ├── Component │ └── empty └── NotificationAppController.php ├── Lib └── empty ├── Model ├── Behavior │ ├── NotifiableBehavior.php │ └── empty ├── Datasource │ └── empty ├── Notification.php ├── NotificationAppModel.php └── Subject.php ├── README.md ├── Test ├── Case │ ├── Controller │ │ └── Component │ │ │ └── empty │ ├── Model │ │ ├── Behavior │ │ │ ├── NotifiableBehaviorTest.php │ │ │ └── empty │ │ ├── NotificationNotificationTest.php │ │ └── NotificationSubjectTest.php │ └── View │ │ └── Helper │ │ └── empty └── Fixture │ ├── NotificationFixture.php │ ├── PostFixture.php │ ├── SubjectFixture.php │ ├── UserFixture.php │ └── empty ├── Vendor └── empty ├── View └── Helper │ ├── NotificationHelper.php │ └── empty ├── composer.json └── webroot └── empty /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/* 2 | [Cc]onfig/core.php 3 | [Cc]onfig/database.php 4 | app/tmp/* 5 | app/[Cc]onfig/core.php 6 | app/[Cc]onfig/database.php 7 | !empty -------------------------------------------------------------------------------- /Config/Schema/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Config/Schema/empty -------------------------------------------------------------------------------- /Config/Schema/schema.mwb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Config/Schema/schema.mwb -------------------------------------------------------------------------------- /Config/Schema/schema.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Structure de la table `notification_notifications` 3 | -- 4 | 5 | CREATE TABLE `notification_notifications` ( 6 | `id` int(11) NOT NULL AUTO_INCREMENT, 7 | `user_id` int(11) NOT NULL, 8 | `type` varchar(45) NOT NULL, 9 | `read` tinyint(1) NOT NULL, 10 | `created` datetime NOT NULL, 11 | `modified` datetime NOT NULL, 12 | PRIMARY KEY (`id`), 13 | KEY `user_id` (`user_id`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 15 | 16 | -- -------------------------------------------------------- 17 | 18 | -- 19 | -- Structure de la table `notification_subjects` 20 | -- 21 | 22 | CREATE TABLE `notification_subjects` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT, 24 | `notification_id` int(11) NOT NULL, 25 | `model` varchar(45) NOT NULL, 26 | `model_id` int(11) NOT NULL, 27 | PRIMARY KEY (`id`), 28 | KEY `notification_id` (`notification_id`,`model`,`model_id`) 29 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 30 | -------------------------------------------------------------------------------- /Console/Command/Task/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Console/Command/Task/empty -------------------------------------------------------------------------------- /Controller/Component/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Controller/Component/empty -------------------------------------------------------------------------------- /Controller/NotificationAppController.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class NotifiableBehavior extends ModelBehavior { 9 | 10 | /** 11 | * Default settings 12 | * 13 | * @var array 14 | */ 15 | public $default = array( 16 | 'subjects' => array(), 17 | ); 18 | 19 | 20 | public function setup(Model $Model, $settings = array()){ 21 | if (!isset($this->__settings[$Model->alias])) { 22 | $this->__settings[$Model->alias] = $this->default; 23 | } 24 | $this->__settings[$Model->alias] = array_merge($this->__settings[$Model->alias], is_array($settings) ? $settings : array()); 25 | 26 | // bind the Like model to the current model 27 | $Model->bindModel(array( 28 | 'hasMany' => array( 29 | 'Notification' => array( 30 | 'className' => 'Notification.Notification', 31 | 'foreignKey' => 'user_id', 32 | ) 33 | ) 34 | ), false); 35 | 36 | $belongsTo = array(); 37 | foreach ($this->__settings[$Model->alias]['subjects'] as $subject) { 38 | $belongsTo[$subject] = array( 39 | 'className' => $subject, 40 | 'foreignKey' => 'model_id', 41 | 'conditions' => array('Subject.model' => $subject) 42 | ); 43 | } 44 | $Model->Notification->Subject->bindModel(compact('belongsTo'), false); 45 | 46 | } 47 | 48 | /** 49 | * 50 | * Example : 51 | * 52 | * $this->User->notify(1, 'post_comment', array('User'=>2,'Comment'=>1)); 53 | * 54 | * $this->User->id = 1; 55 | * $this->User->notify('post_comment', array('User'=>2,'Comment'=>1)); 56 | * 57 | */ 58 | public function notify(Model $Model, $user_id, $type, $subjects = array()){ 59 | 60 | if(is_string($user_id) && is_array($type)){ 61 | $subjects = $type; 62 | $type = $user_id; 63 | $user_id = $Model->id; 64 | } 65 | 66 | if(empty($user_id)) return false; 67 | 68 | $notification = array( 69 | 'Notification' => array( 70 | 'user_id' => $user_id, 71 | 'type' => $type, 72 | ), 73 | 'Subject' => array() 74 | ); 75 | 76 | foreach ($subjects as $model => $model_id) { 77 | $notification['Subject'][] = compact('model', 'model_id'); 78 | } 79 | 80 | $Model->Notification->create(); 81 | return $Model->Notification->saveAll($notification); 82 | } 83 | 84 | /** 85 | * 86 | * $notifications = $this->User->getUnreadNotification(1); 87 | * 88 | * $this->User->id = 1; 89 | * $notifications = $this->User->getUnreadNotification(); 90 | * 91 | * $notifications = $this->User->getUnreadNotification(1, array('Notification.created >' => date())); 92 | * 93 | */ 94 | public function getUnreadNotification(Model $Model, $user_id = null, $conditions = array()){ 95 | if(empty($user_id)) $user_id = $Model->id; 96 | return $Model->Notification->getUnread($user_id); 97 | } 98 | 99 | /** 100 | * 101 | * $notifications = $this->User->getLastNotification(1, 5); 102 | */ 103 | public function getLastNotification(Model $Model, $user_id, $limit = 5){ 104 | return $Model->Notification->getLast($user_id, $limit); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /Model/Behavior/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Model/Behavior/empty -------------------------------------------------------------------------------- /Model/Datasource/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Model/Datasource/empty -------------------------------------------------------------------------------- /Model/Notification.php: -------------------------------------------------------------------------------- 1 | array( 25 | 'notempty' => array( 26 | 'rule' => array('notempty'), 27 | //'message' => 'Your custom message here', 28 | //'allowEmpty' => false, 29 | //'required' => false, 30 | //'last' => false, // Stop validation after this rule 31 | //'on' => 'create', // Limit validation to 'create' or 'update' operations 32 | ), 33 | ), 34 | 'read' => array( 35 | 'boolean' => array( 36 | 'rule' => array('boolean'), 37 | //'message' => 'Your custom message here', 38 | //'allowEmpty' => false, 39 | //'required' => false, 40 | //'last' => false, // Stop validation after this rule 41 | //'on' => 'create', // Limit validation to 'create' or 'update' operations 42 | ), 43 | ), 44 | ); 45 | 46 | public $order = array('Notification.created DESC'); 47 | 48 | /** 49 | * belongsTo associations 50 | * 51 | * @var array 52 | */ 53 | // public $belongsTo = array( 54 | // 'User' => array( 55 | // 'className' => 'User', 56 | // 'foreignKey' => 'user_id', 57 | // ) 58 | // ); 59 | 60 | 61 | /** 62 | * hasMany associations 63 | * 64 | * @var array 65 | */ 66 | public $hasMany = array( 67 | 'Subject' => array( 68 | 'className' => 'Notification.Subject', 69 | 'foreignKey' => 'notification_id', 70 | 'dependent' => true, 71 | ) 72 | ); 73 | 74 | public function afterFind($results, $primary = false){ 75 | if($primary){ 76 | $ids = Set::classicExtract($results, '{n}.Notification.id'); 77 | $subjects = $this->Subject->findAllByNotificationId($ids); 78 | foreach ($results as $k => $result) { 79 | $s = Set::extract('/.[notification_id='.$result['Notification']['id'].']', $subjects); 80 | foreach ($s as $t) { 81 | $results[$k][$t['model']] = $t[$t['model']]; 82 | } 83 | } 84 | } 85 | return $results; 86 | } 87 | 88 | public function getUnread($user_id, $limit = false){ 89 | return $this->find('all', array( 90 | 'conditions' => array( 91 | 'Notification.user_id' => $user_id, 92 | 'Notification.read' => false 93 | ), 94 | 'limit' => $limit, 95 | )); 96 | } 97 | 98 | public function getLast($user_id, $limit = 5){ 99 | return $this->find('all', array( 100 | 'conditions' => array( 101 | 'Notification.user_id' => $user_id, 102 | ), 103 | 'limit' => $limit, 104 | )); 105 | } 106 | 107 | public function markAllAsRead($user_id){ 108 | return $this->updateAll( 109 | array('Notification.read'=>true), 110 | array('Notification.user_id'=>$user_id) 111 | ); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /Model/NotificationAppModel.php: -------------------------------------------------------------------------------- 1 | array( 19 | 'className' => 'Notification.Notification', 20 | 'foreignKey' => 'notification_id', 21 | ) 22 | ); 23 | 24 | public function afterFind($results, $primary = false){ 25 | foreach ($results as $k => $result) { 26 | $model = $result['Subject']['model']; 27 | if(array_key_exists($model, $result)){ 28 | $results[$k] = $result[$this->alias]+array($model => $result[$model]); 29 | //$results[$k] = array($this->alias=>$result[$this->alias]+array($model => $result[$model])); 30 | } 31 | } 32 | return $results; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CakePHP Notification Plugin 2 | =========================== 3 | 4 | CakePHP Notification Plugin provide an notification system 5 | 6 | Installation 7 | ------------------------------ 8 | 9 | Download the plugin 10 | 11 | cd app/Plugin 12 | git clone git://github.com/aschelch/cakephp-notification-plugin.git Notification 13 | 14 | 15 | Attach the Notifiable behavior to the user model 16 | 17 | public User extends AppModel{ 18 | $actsAs = array( 19 | 'Notification.Notifiable' => array( 20 | 'subjects' => array('User', 'Post', 'Comment') 21 | ) 22 | ); 23 | } 24 | 25 | 26 | 27 | Usage 28 | ------------------------------ 29 | 30 | Notify the user #1 that the user #2 posted a comment (#123) on user #1's post (#456) 31 | 32 | $this->User->notify(1, 'post_comment', array('User'=>2,'Post'=>456,'Comment'=>123)); 33 | 34 | Create an element in Elements/Notification/post_comment.ctp 35 | 36 | 37 | '.$data['User']['username'].'', ''.$data['Post']['title'].''); ?>
38 | Time->niceShort($data['Notification']['created']); ?> 39 |
40 | 41 | In your layout, display the notifications 42 | 43 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Test/Case/Controller/Component/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Test/Case/Controller/Component/empty -------------------------------------------------------------------------------- /Test/Case/Model/Behavior/NotifiableBehaviorTest.php: -------------------------------------------------------------------------------- 1 | array( 8 | 'subjects' => array('Post', 'User') 9 | )); 10 | 11 | public $hasMany = array('Post'); 12 | 13 | } 14 | 15 | class Post extends CakeTestModel{ 16 | 17 | public $belongsTo = array('User'); 18 | 19 | } 20 | 21 | 22 | class NotifiableBehaviorTest extends CakeTestCase{ 23 | 24 | /** 25 | * Fixtures associated with this test case 26 | * 27 | * @var array 28 | */ 29 | var $fixtures = array( 30 | 'plugin.notification.user', 31 | 'plugin.notification.notification', 32 | 'plugin.notification.subject', 33 | 'plugin.notification.post', 34 | ); 35 | 36 | 37 | /** 38 | * Method executed before each test 39 | * 40 | */ 41 | public function setUp() { 42 | parent::setUp(); 43 | $this->User = ClassRegistry::init('User'); 44 | } 45 | 46 | /** 47 | * Method executed after each test 48 | * 49 | */ 50 | public function tearDown() { 51 | unset($this->User); 52 | parent::tearDown(); 53 | } 54 | 55 | public function testNotify(){ 56 | 57 | $notifications = $this->User->Notification->get(array('conditions'=>array('Notification.user_id'=>1))); 58 | $this->assertEqual(1, count($notifications)); 59 | $this->assertTrue(!empty($notifications[0]['Post'])); 60 | $this->assertTrue(!empty($notifications[0]['User'])); 61 | 62 | $this->assertTrue($this->User->notify(1, 'post_add', array('User'=>2, 'Post'=>2))); 63 | 64 | $notifications = $this->User->Notification->get(array('conditions'=>array('Notification.user_id'=>1))); 65 | $this->assertEqual(2, count($notifications)); 66 | $this->assertTrue(!empty($notifications[1]['Post'])); 67 | $this->assertTrue(!empty($notifications[1]['User'])); 68 | 69 | } 70 | 71 | public function testNotifyWithoutUserId(){ 72 | 73 | $notifications = $this->User->Notification->get(array('conditions'=>array('Notification.user_id'=>1))); 74 | $this->assertEqual(1, count($notifications)); 75 | $this->assertTrue(!empty($notifications[0]['Post'])); 76 | $this->User->id = 1; 77 | 78 | $this->assertTrue($this->User->notify('post_add', array('User'=>2, 'Post'=>2))); 79 | 80 | $notifications = $this->User->Notification->get(array('conditions'=>array('Notification.user_id'=>1))); 81 | $this->assertEqual(2, count($notifications)); 82 | $this->assertTrue(!empty($notifications[1]['Post'])); 83 | $this->assertTrue(!empty($notifications[1]['User'])); 84 | 85 | } 86 | 87 | public function testGetUnreadNotification(){ 88 | $this->assertEqual(0, count($this->User->getUnreadNotification(1))); 89 | $this->assertTrue($this->User->notify(1, 'post_add', array('User'=>2, 'Post'=>2))); 90 | $this->assertEqual(1, count($this->User->getUnreadNotification(1))); 91 | $this->User->id = 1; 92 | $this->assertTrue($this->User->notify('post_add', array('User'=>2, 'Post'=>2))); 93 | $this->assertEqual(2, count($this->User->getUnreadNotification())); 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /Test/Case/Model/Behavior/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Test/Case/Model/Behavior/empty -------------------------------------------------------------------------------- /Test/Case/Model/NotificationNotificationTest.php: -------------------------------------------------------------------------------- 1 | NotificationNotification = ClassRegistry::init('Notification.NotificationNotification'); 43 | } 44 | 45 | /** 46 | * tearDown method 47 | * 48 | * @return void 49 | */ 50 | public function tearDown() { 51 | unset($this->NotificationNotification); 52 | 53 | parent::tearDown(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Test/Case/Model/NotificationSubjectTest.php: -------------------------------------------------------------------------------- 1 | NotificationSubject = ClassRegistry::init('Notification.NotificationSubject'); 28 | } 29 | 30 | /** 31 | * tearDown method 32 | * 33 | * @return void 34 | */ 35 | public function tearDown() { 36 | unset($this->NotificationSubject); 37 | 38 | parent::tearDown(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Test/Case/View/Helper/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Test/Case/View/Helper/empty -------------------------------------------------------------------------------- /Test/Fixture/NotificationFixture.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'), 17 | 'user_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'index'), 18 | 'type' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 45, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'), 19 | 'read' => array('type' => 'boolean', 'null' => false, 'default' => null), 20 | 'created' => array('type' => 'datetime', 'null' => false, 'default' => null), 21 | 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null), 22 | 'indexes' => array( 23 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 24 | 'user_id' => array('column' => 'user_id', 'unique' => 0) 25 | ), 26 | 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'InnoDB') 27 | ); 28 | 29 | /** 30 | * Records 31 | * 32 | * @var array 33 | */ 34 | public $records = array( 35 | array( 36 | 'id' => 1, 37 | 'user_id' => 1, 38 | 'type' => 'post_add', 39 | 'read' => 1, 40 | 'created' => '2013-06-21 18:14:59', 41 | 'modified' => '2013-06-21 18:14:59' 42 | ), 43 | ); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Test/Fixture/PostFixture.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'), 15 | 'user_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'index'), 16 | 'title' => 'string', 17 | 'content' => 'text', 18 | 'indexes' => array( 19 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 20 | ), 21 | 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'InnoDB') 22 | ); 23 | 24 | /** 25 | * Records 26 | * 27 | * @var array 28 | */ 29 | public $records = array( 30 | array( 31 | 'id' => 1, 32 | 'user_id' => 2, 33 | 'title' => 'My first post', 34 | 'content' => 'Lorem ipsum' 35 | ), 36 | array( 37 | 'id' => 2, 38 | 'user_id' => 2, 39 | 'title' => 'My second post', 40 | 'content' => 'Lorem ipsum' 41 | ), 42 | ); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Test/Fixture/SubjectFixture.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'), 16 | 'notification_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'index'), 17 | 'model' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 45, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'), 18 | 'model_id' => array('type' => 'integer', 'null' => false, 'default' => null), 19 | 'indexes' => array( 20 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 21 | 'notification_id' => array('column' => array('notification_id', 'model', 'model_id'), 'unique' => 0) 22 | ), 23 | 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'InnoDB') 24 | ); 25 | 26 | /** 27 | * Records 28 | * 29 | * @var array 30 | */ 31 | public $records = array( 32 | array( 33 | 'id' => 1, 34 | 'notification_id' => 1, 35 | 'model' => 'Post', 36 | 'model_id' => 1 37 | ), 38 | array( 39 | 'id' => 2, 40 | 'notification_id' => 1, 41 | 'model' => 'User', 42 | 'model_id' => 2 43 | ), 44 | ); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Test/Fixture/UserFixture.php: -------------------------------------------------------------------------------- 1 | array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'), 15 | 'username' => 'text', 16 | 'indexes' => array( 17 | 'PRIMARY' => array('column' => 'id', 'unique' => 1), 18 | ), 19 | 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'InnoDB') 20 | ); 21 | 22 | /** 23 | * Records 24 | * 25 | * @var array 26 | */ 27 | public $records = array( 28 | array( 29 | 'id' => 1, 30 | 'username' => 'john', 31 | ), 32 | array( 33 | 'id' => 2, 34 | 'username' => 'matt', 35 | ), 36 | ); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Test/Fixture/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Test/Fixture/empty -------------------------------------------------------------------------------- /Vendor/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/Vendor/empty -------------------------------------------------------------------------------- /View/Helper/NotificationHelper.php: -------------------------------------------------------------------------------- 1 | _View->element('Notification/'.($type?$type.'/':'').$notification['Notification']['type'], array('data'=>$notification)); 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /View/Helper/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/View/Helper/empty -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aschelch/cakephp-notification-plugin", 3 | "description": "CakePHP Notification Plugin provide an notification system", 4 | "type": "cakephp-plugin", 5 | "extra": { 6 | "installer-name": "Notification" 7 | }, 8 | "keywords": ["cakephp", "plugin", "notification"], 9 | "homepage": "https://github.com/aschelch/cakephp-notification-plugin", 10 | "authors": [ 11 | { 12 | "name": "Aurélien Schelcher", 13 | "homepage": "http://www.aschelch.fr", 14 | "role": "Author" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=5.3.0", 19 | "composer/installers": "*" 20 | } 21 | } -------------------------------------------------------------------------------- /webroot/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aschelch/cakephp-notification-plugin/38519ae7d565e38bbdd34d3e2e2f2f5b046b9c34/webroot/empty --------------------------------------------------------------------------------