Commit e970b9f0 authored by Telman Mazhlumov's avatar Telman Mazhlumov

Merge branch 'dev' into 'master'

Dev

See merge request !1
parents b25910ac c029b68d
#!/usr/bin/env php
<?php
use Defa\BxDal\Console\CodeGenerator;
$command = new Symfony\Component\Console\Application();
$command->add(new CodeGenerator());
$command->run();
\ No newline at end of file
{ {
"name": "defa-public/bx-data-abstraction-layer", "name": "defa-public/bx-data-abstraction-layer",
"type": "library", "type": "library",
"description": "Библиотека DAL (data abstraction layer) для 1С-Битрикс. Позволяет получить доступ к данным в упрощенном виде", "description": "Библиотека DAL (data abstraction layer) для 1С-Битрикс. Позволяет получить доступ к данным в упрощенном виде используя свои сущности",
"keywords": [ "keywords": [
"defa", "defa",
"bitrix", "bitrix",
...@@ -19,15 +19,21 @@ ...@@ -19,15 +19,21 @@
} }
], ],
"require": { "require": {
"php" : "~7.0" "php": "^7.1.3",
"ext-json": "*",
"tightenco/collect": "5.5.*",
"nette/php-generator": "^3.0",
"symfony/console": "4.*"
}, },
"require-dev": { "require-dev": {
"nette/php-generator": "^3.0",
"phpunit/phpunit" : "^5.4" "phpunit/phpunit" : "^5.4"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Defa\\BxDal\\": "src" "Defa\\BxDal\\": "src"
} }
} },
"bin": [
"bin/bxdal"
]
} }
\ No newline at end of file
<?php <?php
namespace Defa\BxDal; namespace Defa\BxDal\Base;
use Defa\BxDal\Interfaces\ICacheDriver;
use Defa\BxDal\Interfaces\IDataDriver; use Defa\BxDal\Interfaces\IDataDriver;
use Defa\BxDal\Interfaces\IVOGenerator;
/** /**
* Class BaseDriver * Class BaseDriver
* @package Defa\BxDal * @package Defa\BxDal
*/ */
abstract class BaseDriver implements Interfaces\IDataDriver abstract class Driver implements IDataDriver
{ {
/** /**
* @var string Класс, отвечающий за генерацию VO * @var string модель сущности
*/ */
const VO_GENERATOR = ''; const ENTITY_CLASS = '';
/** /**
* @var int|string последний добавленный идентификатор * @var string последний добавленный идентификатор
*/ */
protected $lastAddedUniqueID; protected $lastAddedUniqueID;
/** /**
* Возвращает объект, который сгенерирует нужный текущему драйверу ValueObject * Возвращает объект, который сгенерирует нужный текущему драйверу Entity
* *
* @return IVOGenerator * @return Entity
*/ */
public static function getVOGenerator(): IVOGenerator public static function createEntity(): Entity
{ {
if (class_exists(static::VO_GENERATOR)) { if (class_exists(static::ENTITY_CLASS)) {
return new {static::VO_GENERATOR}(); return new {
static::ENTITY_CLASS
};
} }
throw new \RuntimeException('Не найден класс генератор VO'); throw new \RuntimeException('Entity class not find');
} }
/** /**
* Позволяет закэшировать выборку с помощью нужного драйвера. Должен вызываться перед fetch * Позволяет закэшировать выборку с помощью нужного драйвера. Должен вызываться перед fetch
* Итоговый вывод будет зависеть от наличия данных в кэше * Итоговый вывод будет зависеть от наличия данных в кэше
* *
* @param string $cacheDriver ? - нужен интерфейс кэширования + добавить реализацию для редиса * @param ICacheDriver $cacheDriver
* @param string $tag * @param string $tag
* @param int $time * @param int $time
* @return IDataDriver * @return IDataDriver
*/ */
public function byCache(string $cacheDriver, string $tag, int $time = 3600): IDataDriver public function byCache(ICacheDriver $cacheDriver, string $tag, int $time = 3600): IDataDriver
{ {
throw new \RuntimeException('Not Implemented');
return $this; return $this;
} }
...@@ -58,5 +61,4 @@ abstract class BaseDriver implements Interfaces\IDataDriver ...@@ -58,5 +61,4 @@ abstract class BaseDriver implements Interfaces\IDataDriver
{ {
return (string)$this->lastAddedUniqueID; return (string)$this->lastAddedUniqueID;
} }
} }
\ No newline at end of file
<?php
namespace Defa\BxDal\Base;
use Defa\BxDal\Interfaces\IEntity;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
use ReflectionProperty;
abstract class Entity implements IEntity
{
/**
* @var array $publicProperties
*/
protected $publicProperties = [];
/**
* Вызывает внутри себя метод initFromArray, для установки всех необходимых полей
*
* IValueObject constructor.
* @param array $rawData ['fieldName' => 'fieldVal']
* @throws ReflectionException
*/
public function __construct(array $rawData)
{
$publicProps = (new ReflectionClass(__CLASS__))->getProperties(ReflectionProperty::IS_PUBLIC);
$this->publicProperties = array_map(static function ($prop) {
/** @var ReflectionProperty $prop */
return $prop->getName();
}, $publicProps);
$this->initFromArray($rawData);
}
/**
* Whether a offset exists
* @param $offset
* @return bool
*/
public function offsetExists($offset): bool
{
return ($offset !== '' ? $this->isAllowedProp($offset) : false);
}
/**
* Offset to retrieve
* @param $offset
* @return mixed
*/
public function offsetGet($offset)
{
if ($offset !== '' && $this->isAllowedProp($offset)) {
return $this->{$offset};
}
throw new InvalidArgumentException('Был передан некорректный ключ (пустой или не существующий');
}
/**
* Offset to set
* @param $offset
* @param $value
*/
public function offsetSet($offset, $value)
{
if ($offset !== '' && $this->isAllowedProp($offset)) {
$this->{$offset} = $value;
} else {
throw new InvalidArgumentException('Был передан некорректный ключ (пустой или не существующий');
}
}
/**
* Offset to unset
* @param $offset
*/
public function offsetUnset($offset)
{
if ($offset !== '' && $this->isAllowedProp($offset)) {
unset($this->{$offset});
} else {
throw new InvalidArgumentException('Был передан некорректный ключ (пустой или не существующий');
}
}
/**
* Инициализирует поля объекта из массива
*
* @param array $rawData
* @return IEntity
*/
abstract public function initFromArray(array $rawData): IEntity;
/**
* Конвертирует текущий объект в массив с ключами и значениями нужного формата
*
* @return array
*/
abstract public function toArray(): array;
/**
* Разрешено ли записывать свойство
*
* @param string $name
* @return bool
*/
protected function isAllowedProp(string $name): bool
{
return property_exists(static::class, $name) && in_array($name, $this->publicProperties, true);
}
}
\ No newline at end of file
<?php
namespace Defa\BxDal\Base;
/**
* TODO: refactor (нужно, чтобы каждый тип обрабатывался в своем обработчике)
*
* Class Mapper
* @package Defa\BxDal\Base
*/
abstract class Mapper
{
/**
*
*/
const PROPERTY_EXIST = false;
/**
*
*/
const FIELD_TYPE_CONVERT_HANDLERS = [];
/**
*
*/
const PROP_TYPE_MAPPER_HANDLERS = [];
/**
*
*/
const PROP_PREFIX = '';
/**
*
*/
const PROP_INNER_PREFIX = '';
/**
* @param string $attributeName
* @return string
*/
abstract public static function convertAttributeToBx(string $attributeName): string;
/**
* @param $values
* @return mixed
*/
abstract public static function convertAttributeValuesToBx(array $values): array;
/**
* @param $values
* @return mixed
*/
abstract public static function convertAttributeValuesFromBx(array $values): array;
/**
* @param string $code
* @param $value
* @return mixed
*/
abstract protected static function processField(string $code, $value);
/**
* @param $value
* @return mixed
*/
abstract protected static function processProp($value);
/**
* @param $value
* @return mixed
*/
abstract protected static function isProperty($value): bool;
/**
* @param $value
* @return mixed
*/
abstract protected static function isMultiple($value): bool;
}
\ No newline at end of file
<?php
namespace Defa\BxDal\Base\Traits;
/**
* Trait HasFields
* @package Defa\BxDal\Base\Traits
*/
trait HasFields
{
/**
* @var array $hiddenFields Поля которые скрываются при вызове методов toArray|toJson
*/
protected $hiddenFields = [];
/**
* @var array $visibleFields Поля которые показыаются при вызове методов toArray|toJson
*/
protected $visibleFields = [];
/**
* @var array $fieldCasts Кастинг полей
*/
protected $fieldCasts = [];
/**
* Вернёт список полей, которые разрешены для показа "наружу"
*
* @param array $fields
* @return array
*/
protected function filterAllowFields(array $fields): array
{
return array_filter($fields, function ($key) {
return !\in_array($key, $this->hiddenFields, true) && \in_array($key, $this->visibleFields, true);
}, ARRAY_FILTER_USE_KEY);
}
/**
* @param $attributeKey
* @param $attributeValue
* @return bool|false|float|int|string
*/
protected function fieldCast($attributeKey, $attributeValue)
{
if (array_key_exists($attributeKey, $this->fieldCasts)){
switch ($this->fieldCasts[$attributeKey]) {
case 'int':
return (int)$attributeValue;
case 'float':
return (float)$attributeValue;
case 'string':
return (string)$attributeValue;
case 'bool':
return (bool)$attributeValue;
case 'array':
case 'json':
return is_array($attributeValue) ? json_encode($attributeValue) : json_decode($attributeValue, true);
case 'serialize':
return is_string($attributeValue) ? unserialize($attributeValue, ['allowed_classes' => false]) : serialize($attributeValue);
case 'date':
return date('d.m.Y', strtotime($attributeValue));
case 'datetime':
return date('d.m.Y H:i:s', strtotime($attributeValue));
case 'timestamp':
return strtotime($attributeValue);
default:
return $attributeValue;
}
}
return $attributeValue;
}
/**
* Возвращает обязательные поля
*
* @return array
*/
public function getRequiredFields(): array
{
return $this->requiredFields;
}
}
\ No newline at end of file
<?php
namespace Defa\BxDal\Base\Traits;
/**
* Trait HasProperties
* @package Defa\BxDal\Base\Traits
*/
trait HasProperties
{
/**
* @var array $hiddenProps Свойства которые скрываются при вызове методов toArray|toJson
*/
protected $hiddenProps = [];
/**
* @var array $visibleProps Свойства которые показыаются при вызове методов toArray|toJson
*/
protected $visibleProps = [];
/**
* @var array $propCasts Кастинг свойств
*/
protected $propCasts = [];
/**
* Вернёт список свойств, которые разрешены для показа "наружу"
*
* @param array $props
* @return array
*/
protected function filterAllowProps(array $props): array
{
return array_filter($props, function ($key) {
return !\in_array($key, $this->hiddenProps, true) && \in_array($key, $this->visibleProps, true);
}, ARRAY_FILTER_USE_KEY);
}
/**
* @param $attributeKey
* @param $attributeValue
* @return bool|false|float|int|string
*/
protected function propCast($attributeKey, $attributeValue)
{
if (array_key_exists($attributeKey, $this->propCasts)){
switch ($this->propCasts[$attributeKey]) {
case 'int':
return (int)$attributeValue;
case 'float':
return (float)$attributeValue;
case 'string':
return (string)$attributeValue;
case 'bool':
return (bool)$attributeValue;
case 'array':
case 'json':
return is_array($attributeValue) ? json_encode($attributeValue) : json_decode($attributeValue, true);
case 'serialize':
return is_string($attributeValue) ? unserialize($attributeValue, ['allowed_classes' => false]) : serialize($attributeValue);
case 'date':
return date('d.m.Y', strtotime($attributeValue));
case 'datetime':
return date('d.m.Y H:i:s', strtotime($attributeValue));
case 'timestamp':
return strtotime($attributeValue);
default:
return $attributeValue;
}
}
return $attributeValue;
}
}
\ No newline at end of file
<?php
namespace Defa\BxDal;
use Defa\BxDal\Interfaces\IVOGenerator;
/**
* Class SchemeGenerator
* @package Defa\BxDal
*/
abstract class BaseVOGenerator implements IVOGenerator
{
}
\ No newline at end of file
<?php
namespace Defa\BxDal;
use Defa\BxDal\Interfaces\IValueObject;
abstract class BaseValueObject implements IValueObject
{
/**
* Вызывает внутри себя метод initFromArray, для установки всех необходимых полей
*
* IValueObject constructor.
* @param array $rawData ['fieldName' => 'fieldVal']
*/
public function __construct(array $rawData)
{
foreach ($rawData as $key => $value) {
if ($this->offsetExists($key)) {
$this->offsetSet($key, $value);
}
}
}
/**
* Whether a offset exists
* @link https://php.net/manual/en/arrayaccess.offsetexists.php
* @param mixed $offset <p>
* An offset to check for.
* </p>
* @return boolean true on success or false on failure.
* </p>
* <p>
* The return value will be casted to boolean if non-boolean was returned.
* @since 5.0.0
*/
public function offsetExists($offset): bool
{
return ($offset !== '' ? property_exists(static::class, $offset) : false);
}
/**
* Offset to retrieve
* @link https://php.net/manual/en/arrayaccess.offsetget.php
* @param mixed $offset <p>
* The offset to retrieve.
* </p>
* @return mixed Can return all value types.
* @since 5.0.0
*/
public function offsetGet($offset)
{
if ($offset !== '' && property_exists(static::class, $offset)) {
return $this->{$offset};
}
throw new \InvalidArgumentException('Был передан некорректный ключ (пустой или не существующий');
}
/**
* Offset to set
* @link https://php.net/manual/en/arrayaccess.offsetset.php
* @param mixed $offset <p>
* The offset to assign the value to.
* </p>
* @param mixed $value <p>
* The value to set.
* </p>
* @return void
* @since 5.0.0
*/
public function offsetSet($offset, $value)
{
if ($offset !== '' && property_exists(static::class, $offset)) {
$this->{$offset} = $value;
} else {
throw new \InvalidArgumentException('Был передан некорректный ключ (пустой или не существующий');
}
}
/**
* Offset to unset
* @link https://php.net/manual/en/arrayaccess.offsetunset.php
* @param mixed $offset <p>
* The offset to unset.
* </p>
* @return void
* @since 5.0.0
*/