Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Commit

Permalink
Language accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
arrilot committed Nov 29, 2018
1 parent 86ece32 commit f34c1c8
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 10 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,35 @@ $users = Product::fromSectionWithCode('sale')->getList();
protected $appends = ['FULL_NAME'];
```

#### Языковые аксессоры

Для многоязычных сайтов типичным является подход, когда для каждого языка создается своё свойство, например, UF_TITLE_RU, UF_TITLE_BY
В этом случае для каждого такого поля можно создать аксессор:
```
// используем далее $section['UF_TITLE'];
public function getUfTitleAttribute()
{
return $this['UF_TITLE_' . strtoupper(LANGUAGE_ID)];
}
// используем далее $element['PROPERTY_TITLE'];
public function getPropertyTitleAttribute()
{
return $this['PROPERTY_TITLE_' . strtoupper(LANGUAGE_ID) . '_VALUE'];
}
```
Так как эти аксессоры однотипны и имеют неприятную особенность засорять модели, то для них можно использовать специальный краткий синтаксис

```
class Product extends ElementModel
{
protected $languageAccessors = [
'PROPERTY_TITLE',
'PROPERTY_FOO'
];
}
```

### События моделей (Model Events)

События позволяют вклиниваться в различные точки жизненного цикла модели и выполнять в них произвольный код.
Expand Down
34 changes: 32 additions & 2 deletions src/Models/ArrayableModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ abstract class ArrayableModel implements ArrayAccess, Arrayable, Jsonable, Itera
* @var array
*/
protected $appends = [];

/**
* Array of language fields with auto accessors.
*
* @var array
*/
protected $languageAccessors = [];

/**
* Array related models indexed by the relation names.
Expand Down Expand Up @@ -74,7 +81,8 @@ public function offsetSet($offset, $value)
*/
public function offsetExists($offset)
{
return $this->getAccessor($offset) ? true : isset($this->fields[$offset]);
return $this->getAccessor($offset) || $this->getAccessorForLanguageField($offset)
? true : isset($this->fields[$offset]);
}

/**
Expand All @@ -100,8 +108,16 @@ public function offsetGet($offset)
{
$fieldValue = isset($this->fields[$offset]) ? $this->fields[$offset] : null;
$accessor = $this->getAccessor($offset);
if ($accessor) {
return $this->$accessor($fieldValue);
}

$accessorForLanguageField = $this->getAccessorForLanguageField($offset);
if ($accessorForLanguageField) {
return $this->$accessorForLanguageField($offset);
}

return $accessor ? $this->$accessor($fieldValue) : $fieldValue;
return $fieldValue;
}

/**
Expand All @@ -127,6 +143,20 @@ private function getAccessor($field)

return method_exists($this, $method) ? $method : false;
}

/**
* Get accessor for language field method name if it exists.
*
* @param string $field
*
* @return string|false
*/
private function getAccessorForLanguageField($field)
{
$method = 'getValueFromLanguageField';

return in_array($field, $this->languageAccessors) && method_exists($this, $method) ? $method : false;
}

/**
* Add value to append.
Expand Down
39 changes: 39 additions & 0 deletions src/Models/BaseBitrixModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ abstract class BaseBitrixModel extends ArrayableModel
{
use ModelEventsTrait;

/**
* @var string|null
*/
protected static $currentLanguage = null;

/**
* Array of model fields keys that needs to be saved with next save().
*
Expand Down Expand Up @@ -455,4 +460,38 @@ public function populateRelation($name, $records)
{
$this->related[$name] = $records;
}

/**
* Setter for currentLanguage.
*
* @param $language
* @return mixed
*/
public static function setCurrentLanguage($language)
{
self::$currentLanguage = $language;
}

/**
* Getter for currentLanguage.
*
* @return string
*/
public static function getCurrentLanguage()
{
return self::$currentLanguage;
}

/**
* Get value from language field according to current language.
*
* @param $field
* @return mixed
*/
protected function getValueFromLanguageField($field)
{
$key = $field . '_' . $this->getCurrentLanguage();

return isset($this->fields[$key]) ? $this->fields[$key] : null;
}
}
13 changes: 13 additions & 0 deletions src/Models/ElementModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,19 @@ protected function internalUpdate($fields, $fieldsSelectedForSave)
return $result;
}

/**
* Get value from language field according to current language.
*
* @param $field
* @return mixed
*/
protected function getValueFromLanguageField($field)
{
$key = $field . '_' . $this->getCurrentLanguage() . '_VALUE';

return isset($this->fields[$key]) ? $this->fields[$key] : null;
}

/**
* @param $value
*/
Expand Down
2 changes: 2 additions & 0 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Arrilot\BitrixBlade\BladeProvider;
use Arrilot\BitrixModels\Debug\IlluminateQueryDebugger;
use Arrilot\BitrixModels\Models\BaseBitrixModel;
use Arrilot\BitrixModels\Models\EloquentModel;
use Bitrix\Main\Config\Configuration;
use DB;
Expand All @@ -23,6 +24,7 @@ class ServiceProvider
*/
public static function register()
{
BaseBitrixModel::setCurrentLanguage(strtoupper(LANGUAGE_ID));
self::bootstrapIlluminatePagination();
}

Expand Down
27 changes: 22 additions & 5 deletions tests/ElementModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ElementModelTest extends TestCase
public function setUp()
{
TestElement::$bxObject = m::mock('obj');
TestElement::setCurrentLanguage('RU');
ElementQuery::$cIblockObject = m::mock('cIblockObject');
}

Expand Down Expand Up @@ -344,16 +345,30 @@ public function testCount()

public function testToArray()
{
$element = new TestElement(1, ['ID' => 1, 'NAME' => 'John Doe']);
$element = new TestElement(1, ['ID' => 1, 'NAME' => 'John Doe', 'PROPERTY_LANG_ACCESSOR_ONE_RU_VALUE' => 'la_ru']);

$this->assertSame(['ID' => 1, 'NAME' => 'John Doe', 'ACCESSOR_THREE' => []], $element->toArray());
$expected = [
'ID' => 1,
'NAME' => 'John Doe',
'ACCESSOR_THREE' => [],
'PROPERTY_LANG_ACCESSOR_ONE_RU_VALUE' => 'la_ru',
'PROPERTY_LANG_ACCESSOR_ONE' => 'la_ru'
];
$this->assertEquals($expected, $element->toArray());
}

public function testToJson()
{
$element = new TestElement(1, ['ID' => 1, 'NAME' => 'John Doe']);
$element = new TestElement(1, ['ID' => 1, 'NAME' => 'John Doe', 'PROPERTY_LANG_ACCESSOR_ONE_RU_VALUE' => 'la_ru',]);

$this->assertSame(json_encode(['ID' => 1, 'NAME' => 'John Doe', 'ACCESSOR_THREE' => []]), $element->toJson());
$expected = [
'ID' => 1,
'NAME' => 'John Doe',
'PROPERTY_LANG_ACCESSOR_ONE_RU_VALUE' => 'la_ru',
'ACCESSOR_THREE' => [],
'PROPERTY_LANG_ACCESSOR_ONE' => 'la_ru'
];
$this->assertEquals(json_encode($expected), $element->toJson());
}

public function testFill()
Expand Down Expand Up @@ -401,7 +416,7 @@ public function testArrayAccess()
public function testAccessors()
{
$element = new TestElement(1);
$element->fill(['ID' => 2, 'NAME' => 'John', 'ACCESSOR_ONE' => 'foo']);
$element->fill(['ID' => 2, 'NAME' => 'John', 'ACCESSOR_ONE' => 'foo', 'PROPERTY_LANG_ACCESSOR_ONE_RU_VALUE' => 'la_ru']);

$this->assertSame('!foo!', $element['ACCESSOR_ONE']);
$this->assertTrue(isset($element['ACCESSOR_ONE']));
Expand All @@ -412,6 +427,8 @@ public function testAccessors()
$this->assertSame([], $element['ACCESSOR_THREE']);
$this->assertTrue(isset($element['ACCESSOR_THREE']));
$this->assertFalse(!empty($element['ACCESSOR_THREE']));
$this->assertTrue(isset($element['PROPERTY_LANG_ACCESSOR_ONE']));
$this->assertSame('la_ru', $element['PROPERTY_LANG_ACCESSOR_ONE']);
}

public function testItPlaysNiceWithOtherBitrixModels()
Expand Down
4 changes: 2 additions & 2 deletions tests/ElementQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ public function testGetListWithKeyBy()
$items = $query->filter(['ACTIVE' => 'N'])->select('ID', 'NAME')->getList();

$expected = [
1 => ['ID' => 1, 'NAME' => 'foo', 'ACCESSOR_THREE' => []],
2 => ['ID' => 2, 'NAME' => 'bar', 'ACCESSOR_THREE' => []],
1 => ['ID' => 1, 'NAME' => 'foo', 'ACCESSOR_THREE' => [], 'PROPERTY_LANG_ACCESSOR_ONE' => null],
2 => ['ID' => 2, 'NAME' => 'bar', 'ACCESSOR_THREE' => [], 'PROPERTY_LANG_ACCESSOR_ONE' => null],
];

$this->assertSame($expected, $items->toArray());
Expand Down
4 changes: 3 additions & 1 deletion tests/Stubs/TestElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
*/
class TestElement extends ElementModel
{
protected $appends = ['ACCESSOR_THREE'];
protected $appends = ['ACCESSOR_THREE', 'PROPERTY_LANG_ACCESSOR_ONE'];

protected $languageAccessors = ['PROPERTY_LANG_ACCESSOR_ONE'];

const IBLOCK_ID = 1;

Expand Down

0 comments on commit f34c1c8

Please sign in to comment.