Skip to content
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
63 changes: 63 additions & 0 deletions local/php_interface/console/install-custom-orm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

if(php_sapi_name() !== 'cli'){
die();
}

define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define("BX_NO_ACCELERATOR_RESET", true);
define("BX_CRONTAB", true);
define("STOP_STATISTICS", true);
define("NO_AGENT_STATISTIC", "Y");
define("DisableEventsCheck", true);
define("NO_AGENT_CHECK", true);

$_SERVER['DOCUMENT_ROOT'] = realpath(__DIR__.'/../../..');


require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");



use Bitrix\Main\Entity\Base;
use Bitrix\Main\Application;
use Otus\Orm\TaskTable;


$entities = [
TaskTable::class
];

foreach ($entities as $entity) {
if (!Application::getConnection($entity::getConnectionName())->isTableExists($entity::getTableName())) {
Base::getInstance($entity)->createDbTable();
}
}

/*
$connection = Application::getConnection();

$tableName = 'aholin_book_author';

if (!$connection->isTableExists($tableName)) {
$connection->queryExecute("
CREATE TABLE {$tableName} (
BOOK_ID int NOT NULL,
AUTHOR_ID int NOT NULL,
PRIMARY KEY (BOOK_ID, AUTHOR_ID)
)
");
}

$tableName = 'aholin_editor_book';

if (!$connection->isTableExists($tableName)) {
$connection->queryExecute("
CREATE TABLE {$tableName} (
BOOK_ID int NOT NULL,
EDITOR_ID int NOT NULL,
PRIMARY KEY (BOOK_ID, EDITOR_ID)
)
");
}*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
<?php

namespace Otus\Models;

use Bitrix\Iblock\ElementTable;
use Bitrix\Iblock\PropertyEnumerationTable;
use Bitrix\Iblock\PropertyTable;
use Bitrix\Main\ArgumentException;
use Bitrix\Main\Data\Cache;
use Bitrix\Main\DB\SqlExpression;
use Bitrix\Main\Entity\ReferenceField;
use Bitrix\Main\NotImplementedException;
use Bitrix\Main\ObjectPropertyException;
use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\Entity\IntegerField;
use Bitrix\Main\Entity\StringField;
use Bitrix\Main\ORM\Data\DeleteResult;
use Bitrix\Main\ORM\Fields\DatetimeField;
use Bitrix\Main\ORM\Fields\ExpressionField;
use Bitrix\Main\SystemException;
use CIBlockElement;

/**
* Class AbstractIblockPropertyValueTable
*
* @package Models
*/
abstract class AbstractIblockPropertyValuesTable extends DataManager
{
const IBLOCK_ID = null;

protected static ?array $properties = null;
protected static ?CIBlockElement $iblockElement = null;

/**
* @return string
*/
public static function getTableName(): string
{
return 'b_iblock_element_prop_s'.static::IBLOCK_ID;
}

/**
* @return string
*/
public static function getTableNameMulti(): string
{
return 'b_iblock_element_prop_m'.static::IBLOCK_ID;
}

/**
* @return array
* @throws ArgumentException
* @throws SystemException
*/
public static function getMap(): array
{
$cache = Cache::createInstance();
$cacheDir = 'iblock_property_map/'.static::IBLOCK_ID;
$multipleValuesTableClass = static::getMultipleValuesTableClass();
static::initMultipleValuesTableClass();

if ($cache->initCache(3600, md5($cacheDir), $cacheDir)) {
$map = $cache->getVars();

} else {
$cache->startDataCache();

$map['IBLOCK_ELEMENT_ID'] = new IntegerField('IBLOCK_ELEMENT_ID', ['primary' => true]);
$map['ELEMENT'] = new ReferenceField(
'ELEMENT',
ElementTable::class,
['=this.IBLOCK_ELEMENT_ID' => 'ref.ID']
);

foreach (static::getProperties() as $property) {
if ($property['MULTIPLE'] === 'Y') {
$map[$property['CODE']] = new ExpressionField(
$property['CODE'],
sprintf('(select group_concat(`VALUE` SEPARATOR "\0") as VALUE from %s as m where m.IBLOCK_ELEMENT_ID = %s and m.IBLOCK_PROPERTY_ID = %d)',
static::getTableNameMulti(),
'%s',
$property['ID']
),
['IBLOCK_ELEMENT_ID'],
['fetch_data_modification' => [static::class, 'getMultipleFieldValueModifier']]
);

if ($property['USER_TYPE'] === 'EList') {
$map[$property['CODE'].'_ELEMENT_NAME'] = new ExpressionField(
$property['CODE'].'_ELEMENT_NAME',
sprintf('(select group_concat(e.NAME SEPARATOR "\0") as VALUE from %s as m join b_iblock_element as e on m.VALUE = e.ID where m.IBLOCK_ELEMENT_ID = %s and m.IBLOCK_PROPERTY_ID = %d)',
static::getTableNameMulti(),
'%s',
$property['ID']
),
['IBLOCK_ELEMENT_ID'],
['fetch_data_modification' => [static::class, 'getMultipleFieldValueModifier']]
);
}

$map[$property['CODE'].'|SINGLE'] = new ReferenceField(
$property['CODE'].'|SINGLE',
$multipleValuesTableClass,
[
'=this.IBLOCK_ELEMENT_ID' => 'ref.IBLOCK_ELEMENT_ID',
'=ref.IBLOCK_PROPERTY_ID' => new SqlExpression('?i', $property['ID'])
]
);

continue;
}

if ($property['PROPERTY_TYPE'] == PropertyTable::TYPE_NUMBER) {
$map[$property['CODE']] = new IntegerField("PROPERTY_{$property['ID']}");
} elseif ($property['USER_TYPE'] === 'Date') {
$map[$property['CODE']] = new DatetimeField("PROPERTY_{$property['ID']}");
} else {
$map[$property['CODE']] = new StringField("PROPERTY_{$property['ID']}");
}

if ($property['PROPERTY_TYPE'] === 'E' && ($property['USER_TYPE'] === 'EList' || is_null($property['USER_TYPE']))) {
$map[$property['CODE'].'_ELEMENT'] = new ReferenceField(
$property['CODE'].'_ELEMENT',
ElementTable::class,
["=this.{$property['CODE']}" => 'ref.ID']
);
}
}

if (empty($map)) {
$cache->abortDataCache();
} else {
$cache->endDataCache($map);
}
}

return $map;
}

/**
* @param array $data
*
* @return bool
*/
public static function add(array $data): bool
{
static::$iblockElement ?? static::$iblockElement = new CIBlockElement();
$fields = [
'NAME' => $data['NAME'],
'IBLOCK_ID' => static::IBLOCK_ID,
'PROPERTY_VALUES' => $data,
];

return static::$iblockElement->Add($fields);
}

/**
* @param $primary
*
* @return DeleteResult
* @throws NotImplementedException
*/
public static function delete($primary): DeleteResult
{
#TODO Implement function
throw new NotImplementedException();
}

/**
* @return array
* @throws ArgumentException
* @throws SystemException
* @throws ObjectPropertyException
*/
public static function getProperties(): array
{
if (isset(static::$properties[static::IBLOCK_ID])) {
return static::$properties[static::IBLOCK_ID];
}

$dbResult = PropertyTable::query()
->setSelect(['ID', 'CODE', 'PROPERTY_TYPE', 'MULTIPLE', 'NAME', 'USER_TYPE'])
->where('IBLOCK_ID', static::IBLOCK_ID)
->exec();
while ($row = $dbResult->fetch()) {
static::$properties[static::IBLOCK_ID][$row['CODE']] = $row;
}

return static::$properties[static::IBLOCK_ID] ?? [];
}

/**
* @param string $code
*
* @return int
* @throws ArgumentException
* @throws ObjectPropertyException
* @throws SystemException
*/
public static function getPropertyId(string $code): int
{
return (int) static::getProperties()[$code]['ID'];
}

/**
* @return array
*/
public static function getMultipleFieldValueModifier(): array
{
return [fn ($value) => array_filter(explode("\0", $value))];
}

/**
* @param int|null $iblockId
*/
public static function clearPropertyMapCache(?int $iblockId = null): void
{
$iblockId = $iblockId ?: static::IBLOCK_ID;
if (empty($iblockId)) {
return;
}

Cache::clearCache(true, "iblock_property_map/$iblockId");
}

/**
* @param string $propertyCode
* @param string $byKey
*
* @return array
* @throws ArgumentException
* @throws ObjectPropertyException
* @throws SystemException
*/
public static function getEnumPropertyOptions(string $propertyCode, string $byKey = 'ID'): array
{
$dbResult = PropertyEnumerationTable::getList([
'select' => ['ID', 'VALUE', 'XML_ID', 'SORT'],
'filter' => ['=PROPERTY.CODE' => $propertyCode, 'PROPERTY.IBLOCK_ID' => static::IBLOCK_ID],
]);
while ($row = $dbResult->fetch()) {
$enumPropertyOptions[$row[$byKey]] = $row;
}

return $enumPropertyOptions ?? [];
}

/**
* @return string
*/
private static function getMultipleValuesTableClass(): string
{
$className = end(explode('\\', static::class));
$namespace = str_replace('\\'.$className, '', static::class);
$className = str_replace('Table', 'MultipleTable', $className);

return $namespace.'\\'.$className;
}

/**
* @return void
*/
private static function initMultipleValuesTableClass(): void
{
$className = end(explode('\\', static::class));
$namespace = str_replace('\\'.$className, '', static::class);
$className = str_replace('Table', 'MultipleTable', $className);

if (class_exists($namespace.'\\'.$className)) {
return;
}

$iblockId = static::IBLOCK_ID;

// $php = <<<PHP
// namespace $namespace;

// class {$className} extends \Models\AbstractIblockPropertyMultipleValuesTable
// {
// const IBLOCK_ID = {$iblockId};
// }

// PHP;
// eval($php);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Otus\Models;

use Bitrix\Main\Entity\ReferenceField;
use Otus\Models\AbstractIblockPropertyValuesTable;
use Otus\Orm\TaskTable;

class CatalogPropertyValuesTable extends AbstractIblockPropertyValuesTable
{
public const IBLOCK_ID = 14;


public static function getMap(): array
{


$map = [
'TASK' => new ReferenceField(
'TASK',
TaskTable::class,
['=this.ID' => 'ref.PRODUCT_ID']
)
];


return array_merge(parent::getMap(), $map);
}
}
Loading