Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add localization for templates and vars, with CakePHP i18n table. #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Controller/Component/NotifierComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,32 @@ public function getNotifications($userId = null, $state = null)

return $query->toArray();
}

/**
* getI18nNotifications
*
* Returns a list of translated notifications.
*
* @param int|null $userId Id of the user.
* @param bool|null $state The state of notifications: `true` for unread, `false` for read, `null` for all.
* @return array
*/
public function getI18nNotifications($userId = null, $state = null)
{
if (!$userId) {
$userId = $this->Controller->Auth->user('id');
}

$model = TableRegistry::get('Notifier.Notifications');

$query = $model->find('translations')->where(['Notifications.user_id' => $userId])->order(['created' => 'desc']);

if (!is_null($state)) {
$query->where(['Notifications.state' => $state]);
}

return $query->toArray();
}

/**
* countNotifications
Expand Down
35 changes: 35 additions & 0 deletions src/Model/Entity/Notification.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* CakeManager (http://cakemanager.org)
* Copyright (c) http://cakemanager.org
Expand All @@ -12,9 +13,11 @@
* @since 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

namespace Notifier\Model\Entity;

use Cake\Core\Configure;
use Cake\ORM\Behavior\Translate\TranslateTrait;
use Cake\ORM\Entity;
use Cake\Utility\Text;

Expand All @@ -24,6 +27,8 @@
class Notification extends Entity
{

use TranslateTrait;

/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
Expand Down Expand Up @@ -150,6 +155,36 @@ protected function _getRead()
return false;
}

/**
* getI18n
*
* Get localized property
*
* @param string $property : `title` or `body`
* @param string|null $lang : language code
* @return type
*/
public function getI18n($property, $lang = null)
{
$templates = Configure::read('Notifier.templates.i18n');

if (array_key_exists($this->_properties['template'], $templates) && array_key_exists($lang, $templates[$this->_properties['template']])) {
$template = $templates[$this->_properties['template']][$lang];

if (isset($this->_translations[$lang]['vars'])) {
$vars = json_decode($this->_translations[$lang]['vars'], true);
} else {
$vars = json_decode($this->_properties['vars'], true);
}

if (isset($template[$property])) {
return Text::insert($template[$property], $vars);
}
}

return '';
}

/**
* Virtual fields
*
Expand Down
4 changes: 4 additions & 0 deletions src/Model/Table/NotificationsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public function initialize(array $config)
$this->displayField('title');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->addBehavior('Translate', [
'fields' => ['vars'],
'allowEmptyTranslations' => false
]);
}

/**
Expand Down
136 changes: 136 additions & 0 deletions src/Utility/NotificationManager.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* CakeManager (http://cakemanager.org)
* Copyright (c) http://cakemanager.org
Expand All @@ -12,6 +13,7 @@
* @since 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

namespace Notifier\Utility;

use Cake\Core\Configure;
Expand Down Expand Up @@ -107,6 +109,76 @@ public function notify($data)
return $data['tracking_id'];
}

/**
* notifyI18n
*
* Sends notifications to specific users.
* The first parameter `$data` is an array with multiple options.
*
* ### Options
* - `users` - An array or int with id's of users who will receive a notification.
* - `roles` - An array or int with id's of roles which all users ill receive a notification.
* - `template` - The template wich will be used.
* - `vars` - The localized variables used in the template.
*
* ### Example
* ```
* NotificationManager::instance()->notify([
* 'users' => 1,
* 'template' => 'newOrder',
* 'vars' => [
* 'en' => [
* 'receiver' => $receiver->name
* 'link' => '/en/order/],
* 'fr' => [
* 'receiver' => $receiver->name
* 'link' => '/fr/order/],
* ],
* ]);
* ```
*
* @param array $data Data with options.
* @return string The tracking_id to follow the notification.
*/
public function notifyI18n($data)
{
$model = TableRegistry::get('Notifier.Notifications');

$_data = [
'users' => [],
'recipientLists' => [],
'template' => 'default',
'vars' => [],
'tracking_id' => $this->getTrackingId()
];

$data = array_merge($_data, $data);

foreach ((array)$data['recipientLists'] as $recipientList) {
$list = (array)$this->getRecipientList($recipientList);
$data['users'] = array_merge($data['users'], $list);
}

foreach ((array)$data['users'] as $user) {
$entity = $model->newEntity();

$entity->set('template', $data['template']);
$entity->set('tracking_id', $data['tracking_id']);

$entity->set('vars', current($data['vars']));
foreach ($data['vars'] as $lang => $vars) {
$entity->translation($lang)->set(['vars' => $vars], ['guard' => false]);
}

$entity->set('state', 1);
$entity->set('user_id', $user);

$model->save($entity);
}

return $data['tracking_id'];
}

/**
* addRecipientList
*
Expand Down Expand Up @@ -182,6 +254,42 @@ public function addTemplate($name, $options = [])
Configure::write('Notifier.templates.' . $name, $options);
}

/**
* addI18nTemplate
*
* Adds localized template.
*
* ### Example
*
* $this->Notifier->addTemplate('newUser', [
* 'en' => [
* 'title' => 'New User: :name',
* 'body' => 'The user :email has been registered'],
* 'fr' => [
* 'title' => 'Nouvel utilisateur : :name',
* 'body' => 'L\'utilisateur :email vient de s\'inscrire'],
* ]);
*
* This code contains the variables `title` and `body`.
*
* @param string $name Unique name.
* @param array $options Options.
* @return void
*/
public function addI18nTemplate($name, $options = [])
{
$_options = [
'en' => [
'title' => 'Notification',
'body' => '',
]
];

$options = array_merge($_options, $options);

Configure::write('Notifier.templates.i18n.' . $name, $options);
}

/**
* getTemplate
*
Expand Down Expand Up @@ -209,6 +317,34 @@ public function getTemplate($name, $type = null)
return false;
}

/**
* getI18nTemplate
*
* Returns the requested localized template.
* If the template or type does not exists, `false` will be returned.
*
* @param string $lang Language code.
* @param string $name Name of the template.
* @param string|null $type The type like `title` or `body`. Leave empty to get the whole template.
* @return array|string|bool
*/
public function getI18nTemplate($lang, $name, $type = null)
{
$templates = Configure::read('Notifier.templates.i18n');

if (array_key_exists($name, $templates)) {
if ($type == 'title') {
return $templates[$name]['title'];
}
if ($type == 'body') {
return $templates[$name]['body'];
}
return $templates[$name];
}

return false;
}

/**
* getTrackingId
*
Expand Down
26 changes: 25 additions & 1 deletion tests/TestCase/Controller/Component/NotifierComponentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class NotifierComponentTest extends TestCase
{

public $fixtures = [
'plugin.notifier.notifications'
'plugin.notifier.notifications',
'core.translates'
];

public function setUp()
Expand Down Expand Up @@ -108,6 +109,29 @@ public function testGetNotifications()
$this->assertEquals(2, count($this->Notifier->getNotifications(2, false)));
}

public function testGetI18nNotifications()
{
$this->Manager->notify(['users' => [1, 1, 1, 2, 2]]);

$this->assertEquals(3, count($this->Notifier->getI18nNotifications(1)));
$this->assertEquals(3, count($this->Notifier->getI18nNotifications(1, true)));
$this->assertEquals(0, count($this->Notifier->getI18nNotifications(1, false)));
$this->assertEquals(2, count($this->Notifier->getI18nNotifications(2)));
$this->assertEquals(2, count($this->Notifier->getI18nNotifications(2, true)));
$this->assertEquals(0, count($this->Notifier->getI18nNotifications(2, false)));

$this->Notifier->markAsRead(2, 1);
$this->Notifier->markAsRead(5, 2);
$this->Notifier->markAsRead(6, 2);

$this->assertEquals(3, count($this->Notifier->getI18nNotifications(1)));
$this->assertEquals(2, count($this->Notifier->getI18nNotifications(1, true)));
$this->assertEquals(1, count($this->Notifier->getI18nNotifications(1, false)));
$this->assertEquals(2, count($this->Notifier->getI18nNotifications(2)));
$this->assertEquals(0, count($this->Notifier->getI18nNotifications(2, true)));
$this->assertEquals(2, count($this->Notifier->getI18nNotifications(2, false)));
}

public function testMarkAsReadWithAuth()
{
$this->Manager->notify(['users' => [1, 1, 1, 1, 1]]);
Expand Down
49 changes: 48 additions & 1 deletion tests/TestCase/Model/Table/NotificationsTableTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* CakeManager (http://cakemanager.org)
* Copyright (c) http://cakemanager.org
Expand All @@ -12,8 +13,10 @@
* @since 1.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

namespace Notifier\Test\TestCase\Model\Table;

use Cake\I18n\I18n;
use Cake\ORM\TableRegistry;
use Cake\TestSuite\TestCase;
use Notifier\Model\Table\NotificationsTable;
Expand All @@ -24,9 +27,10 @@
*/
class NotificationsTableTest extends TestCase
{

public $fixtures = [
'plugin.notifier.notifications',
'core.translates'
];

public function setUp()
Expand Down Expand Up @@ -65,4 +69,47 @@ public function testEntity()
$this->assertEquals('New Notification', $entity->title);
$this->assertEquals('Bob has sent Leonardo a notification about Programming Stuff', $entity->body);
}

public function testI18nEntity()
{
NotificationManager::instance()->addI18nTemplate('newOrder', [
'en' => [
'title' => 'New order',
'body' => ':username bought :product'
],
'fr' => [
'title' => 'Nouvelle commande',
'body' => ':username a acheté :product'
]
]);

$notify = NotificationManager::instance()->notifyI18n([
'users' => 1,
'template' => 'newOrder',
'vars' => [
'en' => [
'username' => 'Bob',
'product' => 'a car'
],
'fr' => [
'username' => 'Bob',
'product' => 'une voiture'
]
]
]);

I18n::locale('en');
$entity = $this->Notifications->get(2);

$this->assertEquals('newOrder', $entity->template);
$this->assertEquals('New order', $entity->getI18n('title', 'en'));
$this->assertEquals('Bob bought a car', $entity->getI18n('body', 'en'));

I18n::locale('fr');
$entity = $this->Notifications->get(2);

$this->assertEquals('newOrder', $entity->template);
$this->assertEquals('Nouvelle commande', $entity->getI18n('title', 'fr'));
$this->assertEquals('Bob a acheté une voiture', $entity->getI18n('body', 'fr'));
}
}
Loading