Last active
April 8, 2022 15:02
-
-
Save keulu/b54791e968231ed438d4cc3dec893aa0 to your computer and use it in GitHub Desktop.
Provide an i18n Model for Codeigniter4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace Libraries\Core; | |
/** | |
* How to use : | |
* | |
* setup your configuration : | |
* | |
* in Config/App search for $defaultLocale and configure your $supportedLocales | |
* | |
* | |
* setup your model : | |
* | |
* <?php namespace App\Models; | |
* | |
* use Libraries\Core\MY_I18n_Model; | |
* | |
* class JobModel extends MY_I18n_Model | |
* { | |
* protected $table = 'jobs'; | |
* protected $primaryKey = 'id'; | |
* | |
* protected $i18nTable = 'jobs_i18n'; | |
* // protected $autofillEmptyFields = true; | |
* protected $i18nKeys = [ | |
* 'title' | |
* ]; | |
* | |
* [...] | |
* } | |
* | |
* Setup your database | |
* | |
* CREATE TABLE IF NOT EXISTS `jobs` ( | |
* `id` int(11) NOT NULL AUTO_INCREMENT, | |
* `title` varchar(50) NOT NULL, | |
* `created_at` datetime NOT NULL, | |
* `updated_at` datetime DEFAULT NULL, | |
* `deleted` tinyint(1) NOT NULL DEFAULT '0', | |
* `deleted_at` datetime DEFAULT NULL, | |
* PRIMARY KEY (`id`) | |
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | |
* | |
* CREATE TABLE IF NOT EXISTS `jobs_i18n` ( | |
* `id` int(11) NOT NULL AUTO_INCREMENT, | |
* `jobs_id` int(11) NOT NULL, | |
* `locale` varchar(7) NOT NULL, | |
* `key` varchar(127) NOT NULL, | |
* `value` varchar(127) NOT NULL, | |
* PRIMARY KEY (`id`), | |
* UNIQUE KEY `unique fileds` (`locale`,`key`,`jobs_id`) | |
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; | |
* | |
* | |
* | |
* the idea is that your key title will automaticaly replaced by the good locale. | |
* | |
* afterFind : your key title will be replaced by the key title in the _i18n table | |
* afterUpdate, your key title will be updated and your _i18n reference too | |
* afterInsert, your key will be created in all $supportedLocales. | |
* if $autofillEmptyFields set to true,all key will take the new value. | |
* if set to false, only $currentLocale will be inserted, the other stay empty | |
* afterDelete. if $useSoftDelete set to true, nothing happens, if set to false, all jobs_id will be removed | |
* | |
* You can use multiple keys per jobs_id. title, description, short_description, [...] as many as you want. | |
* | |
* thats it !! :) | |
*/ | |
use CodeIgniter\Database\BaseBuilder; | |
use Config\App; | |
use CodeIgniter\Model; | |
class MY_I18n_Model extends Model | |
{ | |
/** | |
* locale detection Accept-Language Header - fallback on \Config\App::$defaultLanguage | |
* | |
* @var string | |
*/ | |
private $currentLocale; | |
/** | |
* represent the i18n table_name | |
* | |
* @var string | |
*/ | |
protected $i18nTable; | |
/** | |
* new instance of the query builder | |
* | |
* @var BaseBuilder | |
*/ | |
protected $i18nBuilder; | |
/** | |
* list of keys to translate | |
* | |
* @var array | |
*/ | |
protected $i18nKeys = []; | |
/** | |
* Autofill empty value on insert ? | |
* | |
* @var boolean | |
*/ | |
protected $autofillEmptyFields = false; | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->searchI18nTable(); | |
} | |
/** | |
* Looking for an existing table | |
*/ | |
protected function searchI18nTable() | |
{ | |
if ($this->db->tableExists($this->i18nTable)) { | |
$this->currentLocale = service('request')->getLocale(); | |
$this->i18nBuilder = new BaseBuilder($this->i18nTable, $this->db); | |
$this->afterFind[] = 'i18nAfterFind'; | |
$this->afterInsert[] = 'i18nAfterInsert'; | |
$this->afterUpdate[] = 'i18nAfterUpdate'; | |
$this->afterDelete[] = 'i18nAfterDelete'; | |
} | |
} | |
/** | |
* after Selecting data if single record or multiples. | |
* | |
* @param array $vars The resulting row of data | |
* | |
* @return array The resulting row of data. | |
*/ | |
protected function i18nAfterFind($vars) | |
{ | |
$data_tmp = null; | |
if (!is_null($vars['data'])) { | |
if (isset($vars['id'])) { | |
$data_tmp = $this->joinI18n($vars['data']); | |
} | |
else | |
{ | |
$data_tmp = []; | |
foreach ($vars['data'] as $data) | |
{ | |
$data_tmp[] = $this->joinI18n($data); | |
} | |
} | |
} | |
$vars['data'] = $data_tmp; | |
return $vars; | |
} | |
/** | |
* after Selecting, data is parsed. | |
* | |
* @param array $data The resulting row of data | |
* | |
* @return array The resulting row of data. | |
*/ | |
protected function joinI18n($data) | |
{ | |
$i18n_query = $this->i18nBuilder | |
->where('locale', $this->currentLocale) | |
->where($this->table . '_id', $data['id']) | |
->get(); | |
foreach ($i18n_query->getResult() as $row) | |
{ | |
$data[$row->key] = $row->value; | |
} | |
return $data; | |
} | |
/** | |
* after Delete | |
* | |
* @param array $vars The resulting row of data | |
* | |
* @return array The resulting row of data. | |
*/ | |
protected function i18nAfterDelete($vars) | |
{ | |
if ($vars['purge'] === true) { | |
$this->i18nBuilder | |
->where($this->table . '_id', $vars['id']) | |
->delete(); | |
} | |
return $vars; | |
} | |
/** | |
* after Update | |
* | |
* @param array $vars The resulting row of data | |
* | |
* @return array The resulting row of data. | |
*/ | |
protected function i18nAfterUpdate($vars) | |
{ | |
// foreach keys | |
foreach($vars['data'] as $k => $v) | |
{ | |
// If my currentKey is in my $i18nKeys | |
if (in_array($k, $this->i18nKeys)) { | |
$this->i18nBuilder | |
->where('locale', $this->currentLocale) | |
->where($this->table . '_id', $vars['id']) | |
->where('key', $k) | |
->update(['value' => $v]); | |
} | |
} | |
return $vars; | |
} | |
/** | |
* after Insert | |
* | |
* @param array $vars The resulting row of data | |
* | |
* @return array The resulting row of data. | |
*/ | |
protected function i18nAfterInsert($vars) | |
{ | |
$app_config = new \Config\App(); | |
$relatedId = $this->db->insertID(); | |
// For all keys | |
foreach($vars['data'] as $k => $v) | |
{ | |
// If my currentKey is in my $i18nKeys | |
if (in_array($k, $this->i18nKeys)) | |
{ | |
// And for each locales | |
foreach($app_config->supportedLocales as $locale) | |
{ | |
// if autoFill == true | |
// Set very i18n keys with the same data | |
if ($this->autofillEmptyFields) | |
{ | |
$data = [ | |
$this->table . '_id' => $relatedId, | |
'locale' => $locale, | |
'key' => $k, | |
'value' => $v, | |
]; | |
} | |
// if autofill = false | |
// fill current key and let the others empty | |
else | |
{ | |
$data = [ | |
$this->table . '_id' => $relatedId, | |
'locale' => $locale, | |
'key' => $k, | |
]; | |
// select good locale | |
if ($locale == $this->currentLocale) | |
{ | |
$data['value'] = $v; | |
} | |
// other fields are empty | |
else | |
{ | |
$data['value'] = ''; | |
} | |
} | |
// insert | |
$this->i18nBuilder->insert($data); | |
} | |
} | |
} | |
return $vars; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yes, multiple traits are fine:
https://www.php.net/manual/en/language.oop5.traits.php#language.oop5.traits.multiple
In general I decide on trait versus extension based on a) whether the functions are likely to be "replaced" and b) whether the developer using the functions will likely be extending other classes and interfaces, which can make mixing confusing or buggy.
From best I can tell in your case I'd agree with @chistel that this seems like a good use of a trait.