Update
This commit is contained in:
212
core/bitrix/modules/main/lib/ClassLocator.php
Normal file
212
core/bitrix/modules/main/lib/ClassLocator.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main;
|
||||
|
||||
use Bitrix\Main\IO\Directory;
|
||||
use Bitrix\Main\IO\File;
|
||||
|
||||
final class ClassLocator
|
||||
{
|
||||
private static array $loadedClasses = [];
|
||||
|
||||
public static function getClassesByNamespace(string $namespace): array
|
||||
{
|
||||
$result = [];
|
||||
$directories = self::getDirectoriesByNamespace($namespace);
|
||||
foreach ($directories as $directory)
|
||||
{
|
||||
$classes = self::getClassesByPath($directory);
|
||||
if (!empty($classes))
|
||||
{
|
||||
$result = array_merge($result, $classes);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function getDirectoriesByNamespace(string $namespaceDirectory): array
|
||||
{
|
||||
$originalNamespaceDirectory = trim($namespaceDirectory, '\\');
|
||||
$namespaceDirectory = self::normalizeNamespace($namespaceDirectory);
|
||||
|
||||
$namespaces = Loader::getNamespaces();
|
||||
|
||||
$namespaceDirectories = $namespaces[$namespaceDirectory] ?? [];
|
||||
|
||||
$directories = [];
|
||||
|
||||
if (empty($namespaceDirectories))
|
||||
{
|
||||
$namespaceParts = explode('\\', trim($namespaceDirectory, '\\'));
|
||||
$originalNamespaceParts = explode('\\', $originalNamespaceDirectory);
|
||||
for ($i = count($namespaceParts); $i >= 0; $i--)
|
||||
{
|
||||
$partNamespace = join('\\', array_slice($namespaceParts, 0, $i)) . '\\';
|
||||
$partNamespaceDirectories = $namespaces[$partNamespace] ?? null;
|
||||
if (empty($partNamespaceDirectories))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($partNamespaceDirectories as $partNamespaceDirectoriesItem)
|
||||
{
|
||||
$originalStylePath =
|
||||
$partNamespaceDirectoriesItem['path']
|
||||
. DIRECTORY_SEPARATOR
|
||||
. join(DIRECTORY_SEPARATOR, array_slice($originalNamespaceParts, $i))
|
||||
;
|
||||
if (is_dir($originalStylePath))
|
||||
{
|
||||
$directories[] = $originalStylePath;
|
||||
continue;
|
||||
}
|
||||
|
||||
$lowerStylePath =
|
||||
$partNamespaceDirectoriesItem['path']
|
||||
. DIRECTORY_SEPARATOR
|
||||
. join(DIRECTORY_SEPARATOR, array_slice($namespaceParts, $i))
|
||||
;
|
||||
if (is_dir($lowerStylePath))
|
||||
{
|
||||
$directories[] = $lowerStylePath;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($namespaceDirectories as $namespaceItem)
|
||||
{
|
||||
$directories[] = $namespaceItem['path'];
|
||||
}
|
||||
}
|
||||
|
||||
$directories = array_unique($directories);
|
||||
|
||||
return array_unique($directories);
|
||||
}
|
||||
|
||||
private static function getClassesByPath($path): array
|
||||
{
|
||||
if (isset(self::$loadedClasses[$path]))
|
||||
{
|
||||
return self::$loadedClasses[$path];
|
||||
}
|
||||
|
||||
$pathFiles = self::getFilesByPath($path);
|
||||
foreach ($pathFiles as $pathFile)
|
||||
{
|
||||
$classesNames = self::getClassesNamesFromFilePath($pathFile);
|
||||
foreach ($classesNames as $className)
|
||||
{
|
||||
if (class_exists($className))
|
||||
{
|
||||
self::$loadedClasses[$path][] = $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::$loadedClasses[$path] ?? [];
|
||||
}
|
||||
|
||||
private static function getFilesByPath(string $path): array
|
||||
{
|
||||
$files = [];
|
||||
$directory = new Directory($path);
|
||||
if ($directory->isExists())
|
||||
{
|
||||
foreach ($directory->getChildren() as $child)
|
||||
{
|
||||
if ($child instanceof File)
|
||||
{
|
||||
$files[] = $child->getPath();
|
||||
}
|
||||
elseif ($child instanceof Directory)
|
||||
{
|
||||
foreach (self::getFilesByPath($child->getPath()) as $file)
|
||||
{
|
||||
$files[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException('Invalid directory path');
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
private static function getClassesNamesFromFilePath(string $filePath): array
|
||||
{
|
||||
$classes = [];
|
||||
$file = new File($filePath);
|
||||
if ($file->isExists() && $file->getExtension() === 'php')
|
||||
{
|
||||
$namespace = '';
|
||||
$tokens = token_get_all($file->getContents());
|
||||
$tokenCount = count($tokens);
|
||||
|
||||
for ($i = 0; $i < $tokenCount; $i++)
|
||||
{
|
||||
if (!is_array($tokens[$i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$tokenType = $tokens[$i][0];
|
||||
|
||||
if ($tokenType === T_NAMESPACE)
|
||||
{
|
||||
$namespace = '';
|
||||
for ($j = $i + 1; $j < $tokenCount; $j++)
|
||||
{
|
||||
if ($tokens[$j] === ';')
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (is_array($tokens[$j]) && in_array($tokens[$j][0], [T_NAME_QUALIFIED, T_STRING, T_NS_SEPARATOR]))
|
||||
{
|
||||
$namespace .= $tokens[$j][1];
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($tokenType === T_CLASS)
|
||||
{
|
||||
$classNameToken = $i + 1;
|
||||
while (
|
||||
isset($tokens[$classNameToken]) &&
|
||||
is_array($tokens[$classNameToken]) &&
|
||||
$tokens[$classNameToken][0] === T_WHITESPACE
|
||||
)
|
||||
{
|
||||
$classNameToken++;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($tokens[$classNameToken]) &&
|
||||
is_array($tokens[$classNameToken]) &&
|
||||
$tokens[$classNameToken][0] === T_STRING
|
||||
)
|
||||
{
|
||||
$className = $tokens[$classNameToken][1];
|
||||
$classes[] = $namespace ? $namespace . '\\' . $className : $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
private static function normalizeNamespace($namespace): string
|
||||
{
|
||||
return trim(strtolower($namespace), '\\') . '\\';
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,11 @@ abstract class AbstractCommand implements CommandInterface
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
throw new CommandException($this, 'Command has unprocessed exception', previous: $e);
|
||||
throw new CommandException(
|
||||
$this,
|
||||
sprintf('Command has unprocessed exception: "%s". Code: "%s"', $e->getMessage(), $e->getCode()),
|
||||
previous: $e
|
||||
);
|
||||
}
|
||||
|
||||
$this->afterRun();
|
||||
|
||||
@@ -53,7 +53,7 @@ class EntityCollection implements EntityCollectionInterface
|
||||
|
||||
foreach ($this->items as $key => $item)
|
||||
{
|
||||
if (call_user_func($callback, $item, $key))
|
||||
if ($callback($item, $key))
|
||||
{
|
||||
return $item;
|
||||
}
|
||||
|
||||
@@ -184,6 +184,16 @@ class Image
|
||||
return $this->engine->resize($source, $destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blurs the image.
|
||||
* @param int $sigma
|
||||
* @return bool
|
||||
*/
|
||||
public function blur(int $sigma): bool
|
||||
{
|
||||
return $this->engine->blur($sigma);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a mask to the image (convolution).
|
||||
* @param Image\Mask $mask
|
||||
|
||||
@@ -198,6 +198,15 @@ abstract class Engine
|
||||
*/
|
||||
abstract public function resize(Rectangle $source, Rectangle $destination);
|
||||
|
||||
/**
|
||||
* Blur the image.
|
||||
*
|
||||
* @param int $sigma
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function blur(int $sigma): bool;
|
||||
|
||||
/**
|
||||
* Applies a mask to the image (convolution).
|
||||
* @param Mask $mask
|
||||
|
||||
@@ -173,6 +173,72 @@ class Gd extends Engine
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function blur(int $sigma): bool
|
||||
{
|
||||
if ($this->resource === null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$sigma = max(1, min(100, round($sigma)));
|
||||
|
||||
$originalWidth = $this->getWidth();
|
||||
$originalHeight = $this->getHeight();
|
||||
|
||||
$minScale = 0.5;
|
||||
$smallestWidth = ceil($originalWidth * (1 - pow($minScale, 1.0 / $sigma)));
|
||||
$smallestHeight = ceil($originalHeight * (1 - pow($minScale, 1.0 / $sigma)));
|
||||
|
||||
$prevImage = $this->resource;
|
||||
$prevWidth = $originalWidth;
|
||||
$prevHeight = $originalHeight;
|
||||
$nextImage = $this->resource;
|
||||
$nextWidth = 0;
|
||||
$nextHeight = 0;
|
||||
|
||||
for ($i = 1; $i <= $sigma; $i += 1)
|
||||
{
|
||||
$denominator = (1 - pow($minScale, 1.0 / $i));
|
||||
$nextWidth = (int)round($smallestWidth / $denominator);
|
||||
$nextHeight = (int)round($smallestHeight / $denominator);
|
||||
$nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
|
||||
if ($this->format == File\Image::FORMAT_PNG || $this->format == File\Image::FORMAT_WEBP)
|
||||
{
|
||||
imagealphablending($nextImage, false);
|
||||
imagesavealpha($nextImage, true);
|
||||
}
|
||||
|
||||
imagecopyresampled($nextImage, $prevImage, 0, 0, 0, 0, $nextWidth, $nextHeight, $prevWidth, $prevHeight);
|
||||
imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);
|
||||
if ($prevImage !== $this->resource)
|
||||
{
|
||||
imagedestroy($prevImage);
|
||||
}
|
||||
|
||||
$prevImage = $nextImage;
|
||||
$prevWidth = $nextWidth;
|
||||
$prevHeight = $nextHeight;
|
||||
}
|
||||
|
||||
if ($this->format == File\Image::FORMAT_PNG || $this->format == File\Image::FORMAT_WEBP)
|
||||
{
|
||||
imagealphablending($this->resource, false);
|
||||
imagesavealpha($this->resource, true);
|
||||
}
|
||||
|
||||
imagecopyresampled($this->resource, $nextImage, 0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
|
||||
imagefilter($this->resource, IMG_FILTER_GAUSSIAN_BLUR);
|
||||
if ($nextImage !== $this->resource)
|
||||
{
|
||||
imagedestroy($nextImage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -264,6 +264,22 @@ class Imagick extends Engine
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function blur(int $sigma): bool
|
||||
{
|
||||
if ($this->image === null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$sigma = max(1, min(100, round($sigma)));
|
||||
$this->image->blurImage(0, $sigma);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -4,11 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bitrix\Main\Messenger\Internals\Storage\Db\Model;
|
||||
|
||||
use Bitrix\Main\Entity\IntegerField;
|
||||
use Bitrix\Main\Entity\TextField;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Event;
|
||||
use Bitrix\Main\ORM\EventResult;
|
||||
use Bitrix\Main\ORM\Fields\IntegerField;
|
||||
use Bitrix\Main\ORM\Fields\TextField;
|
||||
use Bitrix\Main\ORM\Fields\DatetimeField;
|
||||
use Bitrix\Main\ORM\Fields\StringField;
|
||||
use Bitrix\Main\Type\DateTime;
|
||||
|
||||
@@ -9,4 +9,5 @@ enum Type: string
|
||||
case Integer = 'is_int';
|
||||
case String = 'is_string';
|
||||
case Float = 'is_float';
|
||||
case Numeric = 'is_numeric';
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ class AccessCode
|
||||
AC_ACCESS_TEAM_DIRECTOR = '^(' . self::ACCESS_TEAM_DIRECTOR . ')(\d+)?$',
|
||||
AC_ACCESS_TEAM_EMPLOYEE = '^(' . self::ACCESS_TEAM_EMPLOYEE . ')(\d+)?$',
|
||||
AC_ACCESS_TEAM_DEPUTY = '^(' . self::ACCESS_TEAM_DEPUTY . ')(\d+)?$',
|
||||
AC_STRUCTURE_TEAM = '^(SNT)(\d+)$',
|
||||
AC_ALL_STRUCTURE_TEAM = '^(SNTR)(\d+)$',
|
||||
AC_STRUCTURE_DEPARTMENT = '^(SND)(\d+)$',
|
||||
AC_ALL_STRUCTURE_DEPARTMENT = '^(SNDR)(\d+)$';
|
||||
AC_ALL_STRUCTURE_DEPARTMENT = '^(SNDR)(\d+)$',
|
||||
AC_STRUCTURE_TEAM = '^(SNT)(\d+)$',
|
||||
AC_ALL_STRUCTURE_TEAM = '^(SNTR)(\d+)$';
|
||||
|
||||
public const
|
||||
TYPE_USER = 'users',
|
||||
@@ -53,8 +53,8 @@ class AccessCode
|
||||
TYPE_ACCESS_TEAM_DEPUTY = 'access_team_deputy',
|
||||
TYPE_CHAT = 'chat',
|
||||
TYPE_OTHER = 'other',
|
||||
TYPE_STRUCTURE_TEAM = 'structureteams',
|
||||
TYPE_STRUCTURE_DEPARTMENT = 'structuredepartments';
|
||||
TYPE_STRUCTURE_DEPARTMENT = 'structuredepartments',
|
||||
TYPE_STRUCTURE_TEAM = 'structureteams';
|
||||
|
||||
public static $map = [
|
||||
self::AC_DEPARTMENT => self::TYPE_DEPARTMENT,
|
||||
@@ -71,10 +71,10 @@ class AccessCode
|
||||
self::AC_ACCESS_TEAM_DIRECTOR => self::TYPE_ACCESS_TEAM_DIRECTOR,
|
||||
self::AC_ACCESS_TEAM_EMPLOYEE => self::TYPE_ACCESS_TEAM_EMPLOYEE,
|
||||
self::AC_ACCESS_TEAM_DEPUTY => self::TYPE_ACCESS_TEAM_DEPUTY,
|
||||
self::AC_STRUCTURE_DEPARTMENT => self::TYPE_STRUCTURE_DEPARTMENT,
|
||||
self::AC_ALL_STRUCTURE_DEPARTMENT => self::TYPE_STRUCTURE_DEPARTMENT,
|
||||
self::AC_STRUCTURE_TEAM => self::TYPE_STRUCTURE_TEAM,
|
||||
self::AC_ALL_STRUCTURE_TEAM => self::TYPE_STRUCTURE_TEAM,
|
||||
self::AC_STRUCTURE_DEPARTMENT => self::TYPE_STRUCTURE_DEPARTMENT,
|
||||
self::AC_ALL_STRUCTURE_DEPARTMENT => self::TYPE_STRUCTURE_DEPARTMENT,
|
||||
];
|
||||
|
||||
private $accessCode;
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
namespace Bitrix\Main\Access\Entity;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Query\Query;
|
||||
use Bitrix\Main\ORM\Data;
|
||||
|
||||
class DataManager extends Entity\DataManager
|
||||
class DataManager extends Data\DataManager
|
||||
{
|
||||
public static function deleteList(array $filter)
|
||||
{
|
||||
@@ -24,4 +24,4 @@ class DataManager extends Entity\DataManager
|
||||
Query::buildFilterSql($entity, $filter)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
@@ -8,12 +9,13 @@
|
||||
|
||||
namespace Bitrix\Main\Access\Permission;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\NotSupportedException;
|
||||
use Bitrix\Main\ORM\Data\Result;
|
||||
use Bitrix\Main\ORM\Event;
|
||||
use Bitrix\Main\Access\Entity\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
use Bitrix\Main\ORM\EntityError;
|
||||
|
||||
Loc::loadMessages(__FILE__);
|
||||
|
||||
@@ -22,17 +24,17 @@ abstract class AccessPermissionTable extends DataManager
|
||||
public static function getMap()
|
||||
{
|
||||
return [
|
||||
new Entity\IntegerField('ID', [
|
||||
new Fields\IntegerField('ID', [
|
||||
'autocomplete' => true,
|
||||
'primary' => true
|
||||
]),
|
||||
new Entity\IntegerField('ROLE_ID', [
|
||||
new Fields\IntegerField('ROLE_ID', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\StringField('PERMISSION_ID', [
|
||||
new Fields\StringField('PERMISSION_ID', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\IntegerField('VALUE', [
|
||||
new Fields\IntegerField('VALUE', [
|
||||
'required' => true
|
||||
])
|
||||
];
|
||||
@@ -51,7 +53,7 @@ abstract class AccessPermissionTable extends DataManager
|
||||
{
|
||||
if (empty($primary))
|
||||
{
|
||||
$result->addError(new Entity\EntityError(Loc::getMessage('ACCESS_PERMISSION_PARENT_VALIDATE_ERROR')));
|
||||
$result->addError(new EntityError(Loc::getMessage('ACCESS_PERMISSION_PARENT_VALIDATE_ERROR')));
|
||||
return;
|
||||
}
|
||||
$data = static::loadUpdateRow($primary, $data);
|
||||
@@ -59,7 +61,7 @@ abstract class AccessPermissionTable extends DataManager
|
||||
|
||||
if (!static::validateRow($data))
|
||||
{
|
||||
$result->addError(new Entity\EntityError(Loc::getMessage('ACCESS_PERMISSION_PARENT_VALIDATE_ERROR')));
|
||||
$result->addError(new EntityError(Loc::getMessage('ACCESS_PERMISSION_PARENT_VALIDATE_ERROR')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,4 +182,4 @@ abstract class AccessPermissionTable extends DataManager
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
@@ -8,24 +9,24 @@
|
||||
|
||||
namespace Bitrix\Main\Access\Role;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Access\Entity\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
|
||||
abstract class AccessRoleRelationTable extends DataManager
|
||||
{
|
||||
public static function getMap()
|
||||
{
|
||||
return [
|
||||
new Entity\IntegerField('ID', [
|
||||
new Fields\IntegerField('ID', [
|
||||
'autocomplete' => true,
|
||||
'primary' => true
|
||||
]),
|
||||
new Entity\IntegerField('ROLE_ID', [
|
||||
new Fields\IntegerField('ROLE_ID', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\StringField('RELATION', [
|
||||
new Fields\StringField('RELATION', [
|
||||
'required' => true
|
||||
])
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
*/
|
||||
namespace Bitrix\Main\Access\Role;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Access\Entity\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
|
||||
abstract class AccessRoleTable extends DataManager
|
||||
{
|
||||
public static function getMap()
|
||||
{
|
||||
return [
|
||||
new Entity\IntegerField('ID', [
|
||||
new Fields\IntegerField('ID', [
|
||||
'autocomplete' => true,
|
||||
'primary' => true
|
||||
]),
|
||||
new Entity\StringField('NAME', [
|
||||
new Fields\StringField('NAME', [
|
||||
'required' => true,
|
||||
])
|
||||
];
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
*/
|
||||
namespace Bitrix\Main\Analytics;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Security\Random;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
|
||||
/**
|
||||
* Class CounterDataTable
|
||||
@@ -26,7 +27,7 @@ use Bitrix\Main\Security\Random;
|
||||
* @method static \Bitrix\Main\Analytics\EO_CounterData wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Analytics\EO_CounterData_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class CounterDataTable extends Entity\DataManager
|
||||
class CounterDataTable extends DataManager
|
||||
{
|
||||
public static function getTableName()
|
||||
{
|
||||
@@ -36,14 +37,14 @@ class CounterDataTable extends Entity\DataManager
|
||||
public static function getMap()
|
||||
{
|
||||
return array(
|
||||
new Entity\StringField('ID', array(
|
||||
new Fields\StringField('ID', array(
|
||||
'primary' => true,
|
||||
'default_value' => array(__CLASS__ , 'getUniqueEventId')
|
||||
)),
|
||||
new Entity\StringField('TYPE', array(
|
||||
new Fields\StringField('TYPE', array(
|
||||
'required' => true
|
||||
)),
|
||||
new Entity\TextField('DATA', array(
|
||||
new Fields\TextField('DATA', array(
|
||||
'serialized' => true
|
||||
))
|
||||
);
|
||||
@@ -51,7 +52,7 @@ class CounterDataTable extends Entity\DataManager
|
||||
|
||||
public static function getUniqueEventId()
|
||||
{
|
||||
list($usec, $sec) = explode(" ", microtime());
|
||||
[$usec, $sec] = explode(" ", microtime());
|
||||
|
||||
$uniqid = mb_substr(base_convert($sec.mb_substr($usec, 2), 10, 36), 0, 16);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2024 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Authentication;
|
||||
@@ -21,6 +21,10 @@ use Bitrix\Main\Service\GeoIp;
|
||||
use Bitrix\Main\Service\GeoIp\Internal\GeonameTable;
|
||||
use Bitrix\Main\Mail;
|
||||
use Bitrix\Main\Localization\LanguageTable;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\ImBot\Bot\Marta;
|
||||
use Bitrix\Im\V2\Message;
|
||||
use Bitrix\Im\V2\Entity\User\User;
|
||||
|
||||
class Device
|
||||
{
|
||||
@@ -53,10 +57,13 @@ class Device
|
||||
$device = static::add($context);
|
||||
$deviceLogin = static::addDeviceLogin($device, $context);
|
||||
|
||||
if (Option::get('main', 'user_device_notify', 'N') === 'Y')
|
||||
$notifyByEmail = (Option::get('main', 'user_device_notify', 'N') === 'Y');
|
||||
$notifyByIm = (Option::get('main', 'user_device_notify_im', 'N') === 'Y' && Main\ModuleManager::isModuleInstalled('im') && Main\ModuleManager::isModuleInstalled('imbot'));
|
||||
|
||||
if ($notifyByEmail || $notifyByIm)
|
||||
{
|
||||
// send notification to the user
|
||||
static::sendEmail($device, $deviceLogin, $user);
|
||||
static::notifyUser($device, $deviceLogin, $user);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -219,15 +226,17 @@ class Device
|
||||
return $login;
|
||||
}
|
||||
|
||||
protected static function sendEmail(EO_UserDevice $device, EO_UserDeviceLogin $deviceLogin, array $user): void
|
||||
protected static function notifyUser(EO_UserDevice $device, EO_UserDeviceLogin $deviceLogin, array $user): void
|
||||
{
|
||||
$site = $user['LID'];
|
||||
if (!$site)
|
||||
// we have settings in the main module options
|
||||
$codes = unserialize(Option::get('main', 'user_device_notify_codes'), ['allowed_classes' => false]);
|
||||
if (!empty($codes))
|
||||
{
|
||||
$site = Main\Context::getCurrent()->getSite();
|
||||
if (!$site)
|
||||
$userCodes = \CAccess::GetUserCodesArray($user['ID']);
|
||||
if (empty(array_intersect($codes, $userCodes)))
|
||||
{
|
||||
$site = \CSite::GetDefSite();
|
||||
// no need to notify
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +246,83 @@ class Device
|
||||
// Devices
|
||||
$deviceTypes = DeviceType::getDescription($lang);
|
||||
|
||||
// geoIP
|
||||
$geonames = [];
|
||||
if (Option::get('main', 'user_device_geodata', 'N') === 'Y')
|
||||
{
|
||||
$geonames = static::getGeoNames($deviceLogin, $lang);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'USER_ID' => $user['ID'],
|
||||
'EMAIL' => $user['EMAIL'],
|
||||
'LOGIN' => $user['LOGIN'],
|
||||
'NAME' => $user['NAME'],
|
||||
'LAST_NAME' => $user['LAST_NAME'],
|
||||
'DEVICE' => $deviceTypes[$device->getDeviceType()],
|
||||
'BROWSER' => $device->getBrowser(),
|
||||
'PLATFORM' => $device->getPlatform(),
|
||||
'USER_AGENT' => $device->getUserAgent(),
|
||||
'IP' => $deviceLogin->getIp(),
|
||||
'DATE' => $deviceLogin->getLoginDate(),
|
||||
'COUNTRY' => $geonames['COUNTRY'] ?? '',
|
||||
'REGION' => $geonames['REGION'] ?? '',
|
||||
'CITY' => $geonames['CITY'] ?? '',
|
||||
'LOCATION' => $geonames['LOCATION'] ?? '',
|
||||
];
|
||||
|
||||
if (Option::get('main', 'user_device_notify', 'N') === 'Y')
|
||||
{
|
||||
// email
|
||||
$site = $user['LID'];
|
||||
if (!$site)
|
||||
{
|
||||
$site = Main\Context::getCurrent()->getSite();
|
||||
if (!$site)
|
||||
{
|
||||
$site = \CSite::GetDefSite();
|
||||
}
|
||||
}
|
||||
|
||||
Mail\Event::send([
|
||||
'EVENT_NAME' => self::EMAIL_EVENT,
|
||||
'C_FIELDS' => $fields,
|
||||
'LID' => $site,
|
||||
'LANGUAGE_ID' => $lang,
|
||||
]);
|
||||
}
|
||||
|
||||
if (Option::get('main', 'user_device_notify_im', 'N') === 'Y' && Main\Loader::includeModule('im') && Main\Loader::includeModule('imbot'))
|
||||
{
|
||||
// chat notification
|
||||
$replace = [];
|
||||
foreach ($fields as $key => $value)
|
||||
{
|
||||
$replace["#$key#"] = $value;
|
||||
}
|
||||
$message = Loc::getMessage('main_device_message', $replace, $lang);
|
||||
$pushMessage = Loc::getMessage('main_device_push_message', null, $lang);
|
||||
|
||||
$infoBotId = Marta::getBotId();
|
||||
if ($infoBotId)
|
||||
{
|
||||
$chat = User::getInstance($user['ID'])->getChatWith($infoBotId);
|
||||
if ($chat)
|
||||
{
|
||||
$chatMessage = new Message();
|
||||
$chatMessage
|
||||
->setMessage($message)
|
||||
->setPushMessage($pushMessage)
|
||||
->setAuthorId($infoBotId)
|
||||
;
|
||||
$chat->sendMessage($chatMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function getGeoNames(EO_UserDeviceLogin $deviceLogin, string $lang): array
|
||||
{
|
||||
// City and Region names
|
||||
$geoids = array_filter([$deviceLogin->getCityGeoid(), $deviceLogin->getRegionGeoid()]);
|
||||
$geonames = GeonameTable::get($geoids);
|
||||
@@ -245,11 +331,13 @@ class Device
|
||||
$region = '';
|
||||
if (!empty($geonames))
|
||||
{
|
||||
$currentLang = Main\Context::getCurrent()->getLanguage();
|
||||
|
||||
$langCode = '';
|
||||
if ($user['LANGUAGE_ID'] != '' && $user['LANGUAGE_ID'] != $currentLang)
|
||||
if ($lang != $currentLang)
|
||||
{
|
||||
$language = LanguageTable::getList([
|
||||
'filter' => ['=LID' => $user['LANGUAGE_ID'], '=ACTIVE' => 'Y'],
|
||||
'filter' => ['=LID' => $lang, '=ACTIVE' => 'Y'],
|
||||
'cache' => ['ttl' => 86400],
|
||||
])->fetchObject();
|
||||
|
||||
@@ -284,29 +372,12 @@ class Device
|
||||
// Combined location
|
||||
$location = implode(', ', array_filter([$city, $region, $country]));
|
||||
|
||||
$fields = [
|
||||
'EMAIL' => $user['EMAIL'],
|
||||
'LOGIN' => $user['LOGIN'],
|
||||
'NAME' => $user['NAME'],
|
||||
'LAST_NAME' => $user['LAST_NAME'],
|
||||
'DEVICE' => $deviceTypes[$device->getDeviceType()],
|
||||
'BROWSER' => $device->getBrowser(),
|
||||
'PLATFORM' => $device->getPlatform(),
|
||||
'USER_AGENT' => $device->getUserAgent(),
|
||||
'IP' => $deviceLogin->getIp(),
|
||||
'DATE' => $deviceLogin->getLoginDate(),
|
||||
return [
|
||||
'COUNTRY' => $country,
|
||||
'REGION' => $region,
|
||||
'CITY' => $city,
|
||||
'LOCATION' => $location,
|
||||
];
|
||||
|
||||
Mail\Event::send([
|
||||
'EVENT_NAME' => self::EMAIL_EVENT,
|
||||
'C_FIELDS' => $fields,
|
||||
'LID' => $site,
|
||||
'LANGUAGE_ID' => $lang,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -138,9 +138,13 @@ class UpdaterService
|
||||
return $result->addError(new Error($error));
|
||||
}
|
||||
|
||||
\CUpdateClient::logUpdates($updateDescription["DATA"]["#"]["ITEM"]);
|
||||
|
||||
\CUpdateClient::finalizeModuleUpdate($updateDescription["DATA"]["#"]["ITEM"]);
|
||||
|
||||
$io->writeln('Done!');
|
||||
|
||||
Option::set('main', 'update_system_update_time', time());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,6 +362,11 @@ class UpdaterService
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($itemsUpdated as $key => $value)
|
||||
{
|
||||
\CUpdateClient::AddMessage2Log("Updated: {$key}" . ($value != '' ? " ({$value})" : ""), "UPD_SUCCESS");
|
||||
}
|
||||
|
||||
\CUpdateClient::finalizeLanguageUpdate($itemsUpdated);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Component;
|
||||
|
||||
use Bitrix\Main\Entity\DataManager;
|
||||
use Bitrix\Main\ORM\Data;
|
||||
|
||||
/**
|
||||
* Class ParametersTable
|
||||
@@ -19,8 +20,7 @@ use Bitrix\Main\Entity\DataManager;
|
||||
* @method static \Bitrix\Main\Component\EO_Parameters wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Component\EO_Parameters_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class ParametersTable
|
||||
extends DataManager
|
||||
class ParametersTable extends Data\DataManager
|
||||
{
|
||||
const SEF_MODE = 'Y';
|
||||
const NOT_SEF_MODE = 'N';
|
||||
@@ -79,7 +79,7 @@ class ParametersTable
|
||||
if (empty($siteId))
|
||||
throw new \Bitrix\Main\ArgumentNullException("siteId");
|
||||
|
||||
$result = new \Bitrix\Main\Entity\DeleteResult();
|
||||
$result = new Data\DeleteResult();
|
||||
|
||||
// event PRE
|
||||
|
||||
@@ -101,7 +101,7 @@ class ParametersTable
|
||||
if (empty($filter))
|
||||
throw new \Bitrix\Main\ArgumentNullException("filter");
|
||||
|
||||
$result = new \Bitrix\Main\Entity\DeleteResult();
|
||||
$result = new Data\DeleteResult();
|
||||
|
||||
$dbResult = static::getList(
|
||||
array(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Bitrix\Main\Config;
|
||||
|
||||
use Bitrix\Main;
|
||||
use Bitrix\Main\Loader;
|
||||
|
||||
final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
{
|
||||
@@ -14,11 +15,11 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
/**
|
||||
* @var Configuration[]
|
||||
*/
|
||||
private static $instances;
|
||||
private $moduleId = null;
|
||||
private $storedData = null;
|
||||
private $data = [];
|
||||
private $isLoaded = false;
|
||||
private static array $instances = [];
|
||||
private ?string $moduleId = null;
|
||||
private ?array $storedData = null;
|
||||
private array $data = [];
|
||||
private bool $isLoaded = false;
|
||||
|
||||
public static function getValue($name)
|
||||
{
|
||||
@@ -26,7 +27,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
return $configuration->get($name);
|
||||
}
|
||||
|
||||
public static function setValue($name, $value)
|
||||
public static function setValue($name, $value): void
|
||||
{
|
||||
$configuration = Configuration::getInstance();
|
||||
$configuration->add($name, $value);
|
||||
@@ -41,13 +42,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*
|
||||
* @param string|null $moduleId
|
||||
* @return Configuration
|
||||
*/
|
||||
public static function getInstance($moduleId = null)
|
||||
public static function getInstance($moduleId = null): self
|
||||
{
|
||||
if (!isset(self::$instances[$moduleId]))
|
||||
{
|
||||
@@ -57,32 +52,32 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
return self::$instances[$moduleId];
|
||||
}
|
||||
|
||||
private static function getPathConfigForModule($moduleId)
|
||||
private static function getPathConfigForModule($moduleId): ?string
|
||||
{
|
||||
if (!$moduleId || !Main\ModuleManager::isModuleInstalled($moduleId))
|
||||
{
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
$moduleConfigPath = getLocalPath("modules/{$moduleId}/.settings.php");
|
||||
$moduleConfigPath = Loader::getLocal("modules/{$moduleId}/.settings.php");
|
||||
if ($moduleConfigPath === false)
|
||||
{
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
return Main\Loader::getDocumentRoot() . $moduleConfigPath;
|
||||
return $moduleConfigPath;
|
||||
}
|
||||
|
||||
private function loadConfiguration()
|
||||
private function loadConfiguration(): void
|
||||
{
|
||||
$this->isLoaded = false;
|
||||
|
||||
if ($this->moduleId)
|
||||
{
|
||||
$path = self::getPathConfigForModule($this->moduleId);
|
||||
if (file_exists($path))
|
||||
if ($path !== null && file_exists($path))
|
||||
{
|
||||
$dataTmp = include($path);
|
||||
$dataTmp = include $path;
|
||||
if (is_array($dataTmp))
|
||||
{
|
||||
$this->data = $dataTmp;
|
||||
@@ -91,18 +86,18 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
}
|
||||
else
|
||||
{
|
||||
if (($path = getLocalPath(self::CONFIGURATION_FILE)) !== false)
|
||||
if (($path = Loader::getLocal(self::CONFIGURATION_FILE)) !== false)
|
||||
{
|
||||
$dataTmp = include Main\Loader::getDocumentRoot() . $path;
|
||||
$dataTmp = include $path;
|
||||
if (is_array($dataTmp))
|
||||
{
|
||||
$this->data = $dataTmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (($pathExtra = getLocalPath(self::CONFIGURATION_FILE_EXTRA)) !== false)
|
||||
if (($pathExtra = Loader::getLocal(self::CONFIGURATION_FILE_EXTRA)) !== false)
|
||||
{
|
||||
$dataTmp = include Main\Loader::getDocumentRoot() . $pathExtra;
|
||||
$dataTmp = include $pathExtra;
|
||||
if (is_array($dataTmp) && !empty($dataTmp))
|
||||
{
|
||||
$this->storedData = $this->data;
|
||||
@@ -117,7 +112,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
$this->isLoaded = true;
|
||||
}
|
||||
|
||||
public function saveConfiguration()
|
||||
public function saveConfiguration(): void
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
@@ -130,7 +125,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = Main\Loader::getDocumentRoot() . getLocalPath(self::CONFIGURATION_FILE);
|
||||
$path = Loader::getLocal(self::CONFIGURATION_FILE);
|
||||
}
|
||||
|
||||
$data = ($this->storedData !== null) ? $this->storedData : $this->data;
|
||||
@@ -143,7 +138,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
file_put_contents($path, "<" . "?php\nreturn " . $data . ";\n");
|
||||
}
|
||||
|
||||
public function add($name, $value)
|
||||
public function add($name, $value): void
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
@@ -162,13 +157,13 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
|
||||
/**
|
||||
* Changes readonly params.
|
||||
* Warning! Developer must use this method very carfully!.
|
||||
* Warning! Developer must use this method very carefully!
|
||||
* You must use this method only if you know what you do!
|
||||
* @param string $name
|
||||
* @param array $value
|
||||
* @return void
|
||||
*/
|
||||
public function addReadonly($name, $value)
|
||||
public function addReadonly($name, $value): void
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
@@ -182,7 +177,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($name)
|
||||
public function delete($name): void
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
@@ -224,8 +219,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
return isset($this->data[$offset]);
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($offset)
|
||||
public function offsetGet($offset): mixed
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
@@ -240,8 +234,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
$this->delete($offset);
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function current()
|
||||
public function current(): mixed
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
@@ -253,21 +246,17 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
return $c === false ? false : $c["value"];
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function next()
|
||||
public function next(): void
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
$this->loadConfiguration();
|
||||
}
|
||||
|
||||
$c = next($this->data);
|
||||
|
||||
return $c === false ? false : $c["value"];
|
||||
next($this->data);
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function key()
|
||||
public function key(): mixed
|
||||
{
|
||||
if (!$this->isLoaded)
|
||||
{
|
||||
@@ -308,7 +297,7 @@ final class Configuration implements \ArrayAccess, \Iterator, \Countable
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
public static function wnc()
|
||||
public static function wnc(): void
|
||||
{
|
||||
Migrator::wnc();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Bitrix\Main\Data\Cache;
|
||||
use Bitrix\Main\Data\CacheEngineInterface;
|
||||
use Bitrix\Main\Data\CacheEngineStatInterface;
|
||||
use Bitrix\Main\Data\Internal\CacheCleanPathTable;
|
||||
use Bitrix\Main\Type\DateTime;
|
||||
|
||||
abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatInterface
|
||||
{
|
||||
@@ -151,7 +152,7 @@ abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatIn
|
||||
{
|
||||
$this->sid = $cacheConfig['sid'];
|
||||
}
|
||||
$this->sid .= '|v1';
|
||||
$this->sid .= '|v1.1';
|
||||
|
||||
if (isset($cacheConfig['actual_data']) && !$this->useLock)
|
||||
{
|
||||
@@ -289,7 +290,7 @@ abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatIn
|
||||
|
||||
protected function getPartition($key): string
|
||||
{
|
||||
return substr(sha1($key), 0, 2);
|
||||
return substr(sha1($key), 0, 4);
|
||||
}
|
||||
|
||||
protected function getInitDirKey($baseDirVersion, $baseDir, $initDir): string
|
||||
@@ -315,7 +316,7 @@ abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatIn
|
||||
* @param bool $create
|
||||
* @return string
|
||||
*/
|
||||
protected function getInitDirVersion($baseDir, $initDir = false, bool $create = true ): string
|
||||
protected function getInitDirVersion($baseDir, $initDir = false, bool $create = true): string
|
||||
{
|
||||
$baseDirVersion = $this->getBaseDirVersion($baseDir);
|
||||
$initDirHash = sha1($baseDir . '|' . $initDir);
|
||||
@@ -523,11 +524,11 @@ abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatIn
|
||||
if ($this->useLock)
|
||||
{
|
||||
$this->set($key . '~', $this->ttlOld, $initDirVersion);
|
||||
$cleanFrom = (new \Bitrix\Main\Type\DateTime())->add('+' . $this->ttlOld . ' seconds');
|
||||
$cleanFrom = (new DateTime())->add('+' . $this->ttlOld . ' seconds');
|
||||
}
|
||||
else
|
||||
{
|
||||
$cleanFrom = (new \Bitrix\Main\Type\DateTime());
|
||||
$cleanFrom = (new DateTime());
|
||||
}
|
||||
|
||||
$this->addCleanPath([
|
||||
@@ -557,7 +558,7 @@ abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatIn
|
||||
{
|
||||
$this->addCleanPath([
|
||||
'PREFIX' => $path,
|
||||
'CLEAN_FROM' => (new \Bitrix\Main\Type\DateTime()),
|
||||
'CLEAN_FROM' => (new DateTime()),
|
||||
'CLUSTER_GROUP' => static::$clusterGroup
|
||||
]);
|
||||
}
|
||||
@@ -601,7 +602,7 @@ abstract class KeyValueEngine implements CacheEngineInterface, CacheEngineStatIn
|
||||
|
||||
$paths = CacheCleanPathTable::query()
|
||||
->setSelect(['ID', 'PREFIX'])
|
||||
->where('CLEAN_FROM', '<=', new \Bitrix\Main\Type\DateTime())
|
||||
->where('CLEAN_FROM', '<=', new DateTime())
|
||||
->where('CLUSTER_GROUP', static::$clusterGroup)
|
||||
->setLimit($count + $delta)
|
||||
->exec();
|
||||
|
||||
@@ -25,8 +25,8 @@ class CacheEngineRedisLight extends CacheEngineRedis
|
||||
if ($filename <> '')
|
||||
{
|
||||
$key = $keyPrefix . '|' . $filename;
|
||||
$this->delFromSet($initListKey, $filename);
|
||||
$this->del($key);
|
||||
$this->delFromSet($initListKey, $filename);
|
||||
}
|
||||
elseif ($initDir != '')
|
||||
{
|
||||
|
||||
@@ -22,8 +22,10 @@ class CacheStorage implements StorageInterface
|
||||
|
||||
public function read(string $key, int $ttl)
|
||||
{
|
||||
$filename = '/' . Cache::getPath($key);
|
||||
if ($this->cacheEngine->read($value, $this->baseDir, self::CACHE_DIR, $filename, $ttl))
|
||||
$initDir = $this->getDirname($key);
|
||||
$filename = $this->getFilename($key);
|
||||
|
||||
if ($this->cacheEngine->read($value, $this->baseDir, $initDir, $filename, $ttl))
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
@@ -33,7 +35,19 @@ class CacheStorage implements StorageInterface
|
||||
|
||||
public function write(string $key, $value, int $ttl)
|
||||
{
|
||||
$filename = '/' . Cache::getPath($key);
|
||||
$this->cacheEngine->write($value, $this->baseDir, self::CACHE_DIR, $filename, $ttl);
|
||||
$initDir = $this->getDirname($key);
|
||||
$filename = $this->getFilename($key);
|
||||
|
||||
$this->cacheEngine->write($value, $this->baseDir, $initDir, $filename, $ttl);
|
||||
}
|
||||
|
||||
private function getDirname(string $key): string
|
||||
{
|
||||
return self::CACHE_DIR . '/'. substr(md5($key), 0, 3);
|
||||
}
|
||||
|
||||
private function getFilename(string $key): string
|
||||
{
|
||||
return '/' . Cache::getPath($key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2024 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Data;
|
||||
@@ -193,18 +194,18 @@ class TaggedCache
|
||||
|
||||
protected function deleteTags(Cache $cache, array $id, array $paths): void
|
||||
{
|
||||
CacheTagTable::deleteByFilter(['@ID' => $id]);
|
||||
CacheTagTable::deleteByFilter(['@RELATIVE_PATH' => array_keys($paths)]);
|
||||
|
||||
foreach ($paths as $path => $v)
|
||||
{
|
||||
$cache->cleanDir($path);
|
||||
unset($this->cacheTag[$path]);
|
||||
}
|
||||
|
||||
CacheTagTable::deleteByFilter(['@ID' => $id]);
|
||||
CacheTagTable::deleteByFilter(['@RELATIVE_PATH' => array_keys($paths)]);
|
||||
}
|
||||
|
||||
public function deleteAllTags(): void
|
||||
{
|
||||
CacheTagTable::cleanTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
core/bitrix/modules/main/lib/db/order.php
Normal file
9
core/bitrix/modules/main/lib/db/order.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\DB;
|
||||
|
||||
enum Order: string
|
||||
{
|
||||
case Asc = 'ASC';
|
||||
case Desc = 'DESC';
|
||||
}
|
||||
@@ -272,22 +272,6 @@ final class ServiceLocator implements ContainerInterface
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->isInterfaceOrAbstractClass($classNameInParams))
|
||||
{
|
||||
if (!isset($this->services[$classNameInParams]))
|
||||
{
|
||||
throw new ServiceNotFoundException(
|
||||
"For {$className} error in params: {$classNameInParams} (abstract or interface) is not registered in ServiceLocator"
|
||||
);
|
||||
}
|
||||
|
||||
[$classOrClosure] = $this->services[$classNameInParams];
|
||||
if (is_string($classOrClosure))
|
||||
{
|
||||
$classNameInParams = $classOrClosure;
|
||||
}
|
||||
}
|
||||
|
||||
$paramsForClass[] = $this->get($classNameInParams);
|
||||
}
|
||||
|
||||
@@ -359,11 +343,4 @@ final class ServiceLocator implements ContainerInterface
|
||||
{
|
||||
return !isset($this->services[$id]);
|
||||
}
|
||||
|
||||
private function isInterfaceOrAbstractClass(string $className): bool
|
||||
{
|
||||
return
|
||||
interface_exists($className)
|
||||
|| (class_exists($className) && (new ReflectionClass($className))->isAbstract());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,12 +219,10 @@ class Binder
|
||||
catch (\TypeError $exception)
|
||||
{
|
||||
throw $exception;
|
||||
// $this->processException($exception);
|
||||
}
|
||||
catch (\ErrorException $exception)
|
||||
{
|
||||
throw $exception;
|
||||
// $this->processException($exception);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -17,6 +17,10 @@ use Bitrix\Main\Errorable;
|
||||
use Bitrix\Main\ArgumentNullException;
|
||||
use Bitrix\Main\ArgumentTypeException;
|
||||
use Bitrix\Main\Context;
|
||||
use Bitrix\Main\Engine\Response\Render\Component;
|
||||
use Bitrix\Main\Engine\Response\Render\Extension;
|
||||
use Bitrix\Main\Engine\Response\Render\View;
|
||||
use Bitrix\Main\Engine\View\ViewPathResolver;
|
||||
use Bitrix\Main\Event;
|
||||
use Bitrix\Main\EventManager;
|
||||
use Bitrix\Main\EventResult;
|
||||
@@ -108,7 +112,7 @@ class Controller implements Errorable, Controllerable
|
||||
}
|
||||
|
||||
/** @see \Bitrix\Main\Engine\ControllerBuilder::build */
|
||||
//propbably should refactor with ControllerBuilder::build
|
||||
//probably should refactor with ControllerBuilder::build
|
||||
|
||||
// override parameters
|
||||
$controller->request = $this->getRequest();
|
||||
@@ -420,11 +424,12 @@ class Controller implements Errorable, Controllerable
|
||||
|
||||
$this->attachFilters($action);
|
||||
|
||||
|
||||
if ($this->prepareParams() &&
|
||||
$this->processBeforeAction($action) === true &&
|
||||
$this->triggerOnBeforeAction($action) === true)
|
||||
{
|
||||
$result = $action->runWithSourceParametersList();
|
||||
$result = $this->getActionResponse($action);
|
||||
|
||||
if ($action instanceof Errorable)
|
||||
{
|
||||
@@ -457,13 +462,18 @@ class Controller implements Errorable, Controllerable
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function writeToLogException(\Throwable $e)
|
||||
protected function getActionResponse(Action $action)
|
||||
{
|
||||
return $action->runWithSourceParametersList();
|
||||
}
|
||||
|
||||
protected function writeToLogException(\Throwable $e): void
|
||||
{
|
||||
$exceptionHandler = Application::getInstance()->getExceptionHandler();
|
||||
$exceptionHandler->writeToLog($e);
|
||||
}
|
||||
|
||||
private function processExceptionInDebug(\Throwable $e)
|
||||
private function processExceptionInDebug(\Throwable $e): void
|
||||
{
|
||||
if ($this->shouldWriteToLogException($e))
|
||||
{
|
||||
@@ -627,6 +637,7 @@ class Controller implements Errorable, Controllerable
|
||||
protected function create($actionName)
|
||||
{
|
||||
$config = $this->getActionConfig($actionName);
|
||||
|
||||
$methodName = $this->generateActionMethodName($actionName);
|
||||
|
||||
if (method_exists($this, $methodName))
|
||||
@@ -646,7 +657,7 @@ class Controller implements Errorable, Controllerable
|
||||
if (!$config)
|
||||
{
|
||||
throw new SystemException(
|
||||
"Could not find description of {$actionName} in {$this::className()}",
|
||||
"Could not find description of $actionName in {$this::className()}",
|
||||
self::EXCEPTION_UNKNOWN_ACTION
|
||||
);
|
||||
}
|
||||
@@ -1085,6 +1096,11 @@ class Controller implements Errorable, Controllerable
|
||||
return $this->errorCollection->toArray();
|
||||
}
|
||||
|
||||
public function hasErrors(): bool
|
||||
{
|
||||
return !$this->errorCollection->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting once error with the necessary code.
|
||||
* @param string $code Code of error.
|
||||
@@ -1094,4 +1110,115 @@ class Controller implements Errorable, Controllerable
|
||||
{
|
||||
return $this->errorCollection->getErrorByCode($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response with component content inside site template.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
public function fooAction()
|
||||
{
|
||||
return $this->renderComponent('bitrix:component.name', 'template-name', [
|
||||
'param' => 'value',
|
||||
]);
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* @see \Bitrix\Main\Engine\Response\Render\Component
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $template
|
||||
* @param array $params
|
||||
* @param bool $withSiteTemplate
|
||||
*
|
||||
* @return Component
|
||||
*/
|
||||
final protected function renderComponent(string $name, string $template = '', array $params = [], bool $withSiteTemplate = true): Component
|
||||
{
|
||||
return new Component(
|
||||
$name,
|
||||
$template,
|
||||
$params,
|
||||
$withSiteTemplate,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render file content.
|
||||
*
|
||||
* Example:
|
||||
* ```php
|
||||
public function fooAction()
|
||||
{
|
||||
return $this->renderView('testfile');
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Equivalent to:
|
||||
* ```php
|
||||
public function fooAction()
|
||||
{
|
||||
return $this->renderView('/local/modules/my.module/views/testfile.php');
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Example with params:
|
||||
* ```php
|
||||
public function fooAction()
|
||||
{
|
||||
return $this->renderView('testfile', [
|
||||
'id' => 123,
|
||||
]);
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* Render only file content, without site template:
|
||||
* ```php
|
||||
public function fooAction()
|
||||
{
|
||||
return $this->renderView('/local/modules/my.module/views/testfile.php', withSiteTemplate: false);
|
||||
}
|
||||
* ```
|
||||
*
|
||||
* @see \Bitrix\Main\Engine\Response\Render\View
|
||||
*
|
||||
* @param string $viewPath
|
||||
* @param array $params
|
||||
* @param bool $withSiteTemplate
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
final protected function renderView(string $viewPath, array $params = [], bool $withSiteTemplate = true): View
|
||||
{
|
||||
$resolver = new ViewPathResolver(
|
||||
$viewPath,
|
||||
'renderView',
|
||||
);
|
||||
|
||||
return new View(
|
||||
$resolver->resolve(),
|
||||
$params,
|
||||
$withSiteTemplate
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render extension. It's not SSR!
|
||||
*
|
||||
* @see \Bitrix\Main\Engine\Response\Render\Extension
|
||||
*
|
||||
* @param string $extension
|
||||
* @param array $params
|
||||
* @param bool $withSiteTemplate
|
||||
*
|
||||
* @return Extension
|
||||
*/
|
||||
final protected function renderExtension(string $extension, array $params = [], bool $withSiteTemplate = true): Extension
|
||||
{
|
||||
return new Extension(
|
||||
$extension,
|
||||
$params,
|
||||
$withSiteTemplate,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine;
|
||||
|
||||
|
||||
@@ -12,6 +13,7 @@ final class ControllerBuilder
|
||||
{
|
||||
$scope = $options['scope'] ?? Controller::SCOPE_AJAX;
|
||||
$currentUser = $options['currentUser'] ?? CurrentUser::get();
|
||||
$request = $options['request'] ?? null;
|
||||
|
||||
$reflectionClass = new \ReflectionClass($controllerClass);
|
||||
if ($reflectionClass->isAbstract())
|
||||
@@ -27,7 +29,7 @@ final class ControllerBuilder
|
||||
/** @var Controller $controller */
|
||||
/** @see \Bitrix\Main\Engine\Controller::__construct */
|
||||
/** @see \Bitrix\Main\Engine\Controller::forward */
|
||||
$controller = $reflectionClass->newInstance();
|
||||
$controller = $reflectionClass->newInstance($request);
|
||||
$controller->setScope($scope);
|
||||
$controller->setCurrentUser($currentUser);
|
||||
|
||||
@@ -38,4 +40,4 @@ final class ControllerBuilder
|
||||
throw new ObjectException("Unable to construct controller {{$controllerClass}}.", $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
62
core/bitrix/modules/main/lib/engine/response/render/base.php
Normal file
62
core/bitrix/modules/main/lib/engine/response/render/base.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render;
|
||||
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\HttpResponse;
|
||||
use CMain;
|
||||
|
||||
abstract class Base extends HttpResponse
|
||||
{
|
||||
abstract protected function renderContent(): void;
|
||||
|
||||
protected function __construct(
|
||||
bool $withSiteTemplate,
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->fillContent($withSiteTemplate);
|
||||
}
|
||||
|
||||
final protected function fillContent(bool $withSiteTemplate): void
|
||||
{
|
||||
global $APPLICATION;
|
||||
|
||||
/**
|
||||
* @var CMain $APPLICATION
|
||||
*/
|
||||
|
||||
$APPLICATION->RestartBuffer();
|
||||
|
||||
if ($withSiteTemplate)
|
||||
{
|
||||
$this->includeHeader();
|
||||
}
|
||||
else
|
||||
{
|
||||
$APPLICATION->ShowAjaxHead();
|
||||
}
|
||||
|
||||
$this->renderContent();
|
||||
|
||||
if ($withSiteTemplate)
|
||||
{
|
||||
$this->includeFooter();
|
||||
}
|
||||
|
||||
$content = $APPLICATION->EndBufferContentMan();
|
||||
|
||||
$this->setContent($content);
|
||||
}
|
||||
|
||||
final protected function includeHeader(): void
|
||||
{
|
||||
require Application::getDocumentRoot() . '/bitrix/modules/main/include/prolog_after.php';
|
||||
}
|
||||
|
||||
final protected function includeFooter(): void
|
||||
{
|
||||
require Application::getDocumentRoot() . '/bitrix/modules/main/include/epilog_before.php';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render;
|
||||
|
||||
use CMain;
|
||||
|
||||
/**
|
||||
* Response with component on site template.
|
||||
*
|
||||
* @see \Bitrix\Main\Engine\Response\Component for AJAX responses.
|
||||
*/
|
||||
final class Component extends Base
|
||||
{
|
||||
public function __construct(
|
||||
private string $name,
|
||||
private string $template,
|
||||
private array $params = [],
|
||||
bool $withSiteTemplate = true,
|
||||
)
|
||||
{
|
||||
parent::__construct($withSiteTemplate);
|
||||
}
|
||||
|
||||
protected function renderContent(): void
|
||||
{
|
||||
global $APPLICATION;
|
||||
|
||||
/**
|
||||
* @var CMain $APPLICATION
|
||||
*/
|
||||
|
||||
$APPLICATION->IncludeComponent(
|
||||
$this->name,
|
||||
$this->template,
|
||||
$this->params
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render\Exception;
|
||||
|
||||
final class InvalidConfigExtensionException extends RenderException
|
||||
{
|
||||
public function __construct(string $extension, string $reason)
|
||||
{
|
||||
parent::__construct(
|
||||
"Invalid config format for extension `{$extension}`: {$reason}",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render\Exception;
|
||||
|
||||
final class NotFoundPathToViewException extends RenderException
|
||||
{
|
||||
/**
|
||||
* @param string $pathOnDocumentRoot
|
||||
*/
|
||||
public function __construct(string $pathOnDocumentRoot)
|
||||
{
|
||||
parent::__construct(
|
||||
"Path to view `$pathOnDocumentRoot` not found on document root.",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render\Exception;
|
||||
|
||||
use Bitrix\Main\SystemException;
|
||||
|
||||
abstract class RenderException extends SystemException
|
||||
{}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render;
|
||||
|
||||
use Bitrix\Main\Engine\Response\Render\Exception\InvalidConfigExtensionException;
|
||||
use Bitrix\Main\Web\Json;
|
||||
use CUtil;
|
||||
|
||||
final class Extension extends Base
|
||||
{
|
||||
public function __construct(
|
||||
private string $extension,
|
||||
private array $params = [],
|
||||
bool $withSiteTemplate = true,
|
||||
)
|
||||
{
|
||||
parent::__construct($withSiteTemplate);
|
||||
}
|
||||
|
||||
protected function renderContent(): void
|
||||
{
|
||||
$html = null;
|
||||
$controllerEntryPoint = $this->getControllerEntryPoint();
|
||||
|
||||
if ($controllerEntryPoint)
|
||||
{
|
||||
$containerId = uniqid('render_container_');
|
||||
$selector = CUtil::JSEscape('#' . $containerId);
|
||||
|
||||
$jsonParams = Json::encode($this->params);
|
||||
|
||||
$html = join('', [
|
||||
"<div id='{$containerId}'></div>",
|
||||
"<script>BX.ready(() => { {$controllerEntryPoint}('{$selector}', {$jsonParams}) });</script>",
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidConfigExtensionException(
|
||||
$this->extension,
|
||||
'`controllerEntrypoint` is not defined in extension config',
|
||||
);
|
||||
}
|
||||
|
||||
\Bitrix\Main\UI\Extension::load($this->extension);
|
||||
|
||||
echo $html;
|
||||
}
|
||||
|
||||
private function getControllerEntryPoint(): ?string
|
||||
{
|
||||
$config = \Bitrix\Main\UI\Extension::getConfig($this->extension);
|
||||
if (isset($config['controllerEntrypoint']))
|
||||
{
|
||||
if (!is_string($config['controllerEntrypoint']))
|
||||
{
|
||||
throw new InvalidConfigExtensionException(
|
||||
$this->extension,
|
||||
'`controllerEntrypoint` in config must be a string with JS function name',
|
||||
);
|
||||
}
|
||||
|
||||
return $config['controllerEntrypoint'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
37
core/bitrix/modules/main/lib/engine/response/render/view.php
Normal file
37
core/bitrix/modules/main/lib/engine/response/render/view.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\Response\Render;
|
||||
|
||||
use CMain;
|
||||
|
||||
/**
|
||||
* Response with static view content.
|
||||
*
|
||||
* @see \Bitrix\Main\Routing\Controllers\PublicPageController for using static page on router.
|
||||
*/
|
||||
final class View extends Base
|
||||
{
|
||||
public function __construct(
|
||||
private string $pathOnDocumentRoot,
|
||||
private array $params = [],
|
||||
bool $withSiteTemplate = true,
|
||||
)
|
||||
{
|
||||
parent::__construct($withSiteTemplate);
|
||||
}
|
||||
|
||||
protected function renderContent(): void
|
||||
{
|
||||
global $APPLICATION;
|
||||
|
||||
/**
|
||||
* @var CMain $APPLICATION
|
||||
*/
|
||||
|
||||
$APPLICATION->IncludeFile(
|
||||
$this->pathOnDocumentRoot,
|
||||
$this->params,
|
||||
[],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\View\Exception;
|
||||
|
||||
use Bitrix\Main\SystemException;
|
||||
|
||||
final class FileNotExistsException extends SystemException
|
||||
{
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(
|
||||
"File `{$path}` not exists"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\View\Exception;
|
||||
|
||||
use Bitrix\Main\SystemException;
|
||||
|
||||
final class InvalidPathOnViewException extends SystemException
|
||||
{
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(
|
||||
"Invalid path to view file: {$path}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\View\Exception;
|
||||
|
||||
use Bitrix\Main\SystemException;
|
||||
|
||||
final class PathOutsideDocumentRootException extends SystemException
|
||||
{
|
||||
public function __construct(string $path)
|
||||
{
|
||||
parent::__construct(
|
||||
"Path `{$path}` is outside the document root"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
122
core/bitrix/modules/main/lib/engine/view/viewpathresolver.php
Normal file
122
core/bitrix/modules/main/lib/engine/view/viewpathresolver.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Engine\View;
|
||||
|
||||
use Bitrix\Main\Diag\Helper;
|
||||
use Bitrix\Main\Engine\View\Exception\FileNotExistsException;
|
||||
use Bitrix\Main\Engine\View\Exception\InvalidPathOnViewException;
|
||||
use Bitrix\Main\Engine\View\Exception\PathOutsideDocumentRootException;
|
||||
use Bitrix\Main\IO\Path;
|
||||
use Bitrix\Main\Loader;
|
||||
use Bitrix\Main\SystemException;
|
||||
|
||||
final class ViewPathResolver
|
||||
{
|
||||
private string $documentRoot;
|
||||
|
||||
public function __construct(
|
||||
private string $viewPath,
|
||||
private string $renderFunctionName,
|
||||
)
|
||||
{
|
||||
$this->documentRoot = Loader::getDocumentRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets path on document root to view file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function resolve(): string
|
||||
{
|
||||
$path = $this->getAbsolutePath();
|
||||
if (!empty($path))
|
||||
{
|
||||
$path = Path::normalize($path);
|
||||
}
|
||||
|
||||
if (is_null($path))
|
||||
{
|
||||
throw new InvalidPathOnViewException($this->viewPath);
|
||||
}
|
||||
elseif (!file_exists($path))
|
||||
{
|
||||
throw new FileNotExistsException($path);
|
||||
}
|
||||
elseif (!str_starts_with($path, $this->documentRoot))
|
||||
{
|
||||
throw new PathOutsideDocumentRootException($this->viewPath);
|
||||
}
|
||||
|
||||
$pathOnDocumentRoot = substr(
|
||||
$path,
|
||||
strlen($this->documentRoot)
|
||||
);
|
||||
|
||||
return $pathOnDocumentRoot;
|
||||
}
|
||||
|
||||
private function getAbsolutePath(): ?string
|
||||
{
|
||||
if (str_starts_with($this->viewPath, '/'))
|
||||
{
|
||||
return $this->documentRoot . $this->viewPath;
|
||||
}
|
||||
|
||||
return $this->getPathToViewOnModule();
|
||||
}
|
||||
|
||||
private function getPathToViewOnModule(): ?string
|
||||
{
|
||||
$moduleId = $this->getModuleId();
|
||||
$postfix = '';
|
||||
|
||||
$extension = pathinfo($this->viewPath, PATHINFO_EXTENSION);
|
||||
if ($extension === '')
|
||||
{
|
||||
$postfix = '.php';
|
||||
}
|
||||
elseif ($extension !== 'php')
|
||||
{
|
||||
throw new SystemException('Invalid extension for view file: ' . $extension);
|
||||
}
|
||||
|
||||
$absolutePath = Loader::getLocal(
|
||||
'modules/' . $moduleId . '/views/' . $this->viewPath . $postfix,
|
||||
);
|
||||
if ($absolutePath !== false)
|
||||
{
|
||||
return $absolutePath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getModuleId(): string
|
||||
{
|
||||
$trace = Helper::getBackTrace();
|
||||
foreach ($trace as $item)
|
||||
{
|
||||
if ($item['function'] === $this->renderFunctionName)
|
||||
{
|
||||
$path = Path::normalize($item['file']);
|
||||
$parts = explode('/', $path);
|
||||
$prevPart = null;
|
||||
foreach ($parts as $part)
|
||||
{
|
||||
if ($part === 'lib')
|
||||
{
|
||||
if (isset($prevPart))
|
||||
{
|
||||
return $prevPart;
|
||||
}
|
||||
}
|
||||
|
||||
$prevPart = $part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new SystemException('Cannot parse module id from path');
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2019 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\EventLog\Internal;
|
||||
@@ -38,8 +38,9 @@ class EventLogTable extends Data\DataManager
|
||||
{
|
||||
return [
|
||||
(new Fields\IntegerField("ID"))
|
||||
->configurePrimary(true)
|
||||
->configureAutocomplete(true),
|
||||
->configurePrimary()
|
||||
->configureAutocomplete()
|
||||
->configureSize(8),
|
||||
(new Fields\DatetimeField("TIMESTAMP_X")),
|
||||
(new Fields\StringField("SEVERITY")),
|
||||
(new Fields\StringField("AUDIT_TYPE_ID")),
|
||||
|
||||
@@ -74,6 +74,8 @@ abstract class EntityDataProvider extends DataProvider
|
||||
'intranetUsersOnly' => true,
|
||||
'fieldName' => $params['fieldName'],
|
||||
'referenceClass' => ($params['referenceClass'] ?? null),
|
||||
'referenceFieldName' => ($params['referenceFieldName'] ?? null),
|
||||
'referenceAdditionalFilter' => ($params['referenceAdditionalFilter'] ?? null),
|
||||
'entityTypeId' => ($params['entityTypeId'] ?? null),
|
||||
'module' => ($params['module'] ?? null),
|
||||
]
|
||||
|
||||
@@ -58,7 +58,7 @@ class HttpRequest extends Request
|
||||
* @param array $files _FILES
|
||||
* @param array $cookies _COOKIE
|
||||
*/
|
||||
public function __construct(Server $server, array $queryString, array $postData, array $files, array $cookies)
|
||||
public function __construct(Server $server, array $queryString, array $postData, array $files, array $cookies, array $jsonData = [])
|
||||
{
|
||||
$request = array_merge($queryString, $postData);
|
||||
parent::__construct($server, $request);
|
||||
@@ -69,7 +69,7 @@ class HttpRequest extends Request
|
||||
$this->cookiesRaw = new Type\ParameterDictionary($cookies);
|
||||
$this->cookies = new Type\ParameterDictionary($this->prepareCookie($cookies));
|
||||
$this->headers = $this->buildHttpHeaders($server);
|
||||
$this->jsonData = new Type\ParameterDictionary();
|
||||
$this->jsonData = new Type\ParameterDictionary($jsonData);
|
||||
}
|
||||
|
||||
private function buildHttpHeaders(Server $server)
|
||||
@@ -594,4 +594,22 @@ class HttpRequest extends Request
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function decodeJsonStrict(): void
|
||||
{
|
||||
if (!$this->isJson())
|
||||
{
|
||||
throw new SystemException('Input is not valid JSON');
|
||||
}
|
||||
if (empty($this->jsonData->getValues()))
|
||||
{
|
||||
$json = Web\Json::decode(static::getInput());
|
||||
if (!is_array($json))
|
||||
{
|
||||
throw new SystemException('Decoded JSON is not an array');
|
||||
}
|
||||
|
||||
$this->jsonData = new Type\ParameterDictionary($json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Bitrix\Main;
|
||||
|
||||
use Bitrix\Main\Config\Configuration;
|
||||
use Bitrix\Main\DI\ServiceLocator;
|
||||
|
||||
/**
|
||||
@@ -49,6 +50,8 @@ class Loader
|
||||
*/
|
||||
protected static $namespaces = [];
|
||||
protected static $autoLoadClasses = [];
|
||||
protected static $aliases = [];
|
||||
protected static $classAliases = [];
|
||||
/**
|
||||
* @var bool Controls throwing exception by requireModule method
|
||||
*/
|
||||
@@ -290,6 +293,26 @@ class Loader
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers class aliases for autoloading.
|
||||
*
|
||||
* @param array $aliases Array with aliases as keys and classes as values.
|
||||
*/
|
||||
public static function registerClassAliases(array $aliases): void
|
||||
{
|
||||
foreach ($aliases as $alias => $class)
|
||||
{
|
||||
$alias = strtolower(ltrim($alias, "\\"));
|
||||
$class = strtolower(ltrim($class, "\\"));
|
||||
|
||||
// one class for an alias
|
||||
self::$aliases[$alias] = $class;
|
||||
// but many aliases for a class
|
||||
self::$classAliases[$class][] = $alias;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers namespaces with custom paths.
|
||||
* e.g. ('Bitrix\Main\Dev', '/home/bitrix/web/site/bitrix/modules/main/dev/lib')
|
||||
@@ -345,15 +368,24 @@ class Loader
|
||||
|
||||
$classLower = strtolower($className);
|
||||
|
||||
// dynamically define the alias for a class
|
||||
if (isset(self::$aliases[$classLower]))
|
||||
{
|
||||
class_alias(self::$aliases[$classLower], $classLower);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static $documentRoot = null;
|
||||
if ($documentRoot === null)
|
||||
{
|
||||
$documentRoot = self::getDocumentRoot();
|
||||
}
|
||||
|
||||
//optimization via direct paths
|
||||
if (isset(self::$autoLoadClasses[$classLower]))
|
||||
{
|
||||
// optimization via direct paths
|
||||
|
||||
$pathInfo = self::$autoLoadClasses[$classLower];
|
||||
if ($pathInfo["module"] != "")
|
||||
{
|
||||
@@ -372,81 +404,93 @@ class Loader
|
||||
{
|
||||
require_once($documentRoot . $pathInfo["file"]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $className))
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
// search the path in namespaces
|
||||
|
||||
$tryFiles = [[
|
||||
"real" => $className,
|
||||
"lower" => $classLower,
|
||||
]];
|
||||
|
||||
if (str_ends_with($classLower, "table"))
|
||||
{
|
||||
// old *Table stored in reserved files
|
||||
$tryFiles[] = [
|
||||
"real" => substr($className, 0, -5),
|
||||
"lower" => substr($classLower, 0, -5),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($tryFiles as $classInfo)
|
||||
{
|
||||
$classParts = explode("\\", $classInfo["lower"]);
|
||||
|
||||
//remove class name
|
||||
array_pop($classParts);
|
||||
|
||||
while (!empty($classParts))
|
||||
if (preg_match("#[^\\\\/a-zA-Z0-9_]#", $className))
|
||||
{
|
||||
//go from the end
|
||||
$namespace = implode("\\", $classParts) . "\\";
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::$namespaces[$namespace]))
|
||||
$tryFiles = [[
|
||||
"real" => $className,
|
||||
"lower" => $classLower,
|
||||
]];
|
||||
|
||||
if (str_ends_with($classLower, "table"))
|
||||
{
|
||||
// old *Table stored in reserved files
|
||||
$tryFiles[] = [
|
||||
"real" => substr($className, 0, -5),
|
||||
"lower" => substr($classLower, 0, -5),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($tryFiles as $classInfo)
|
||||
{
|
||||
$classParts = explode("\\", $classInfo["lower"]);
|
||||
|
||||
//remove class name
|
||||
array_pop($classParts);
|
||||
|
||||
while (!empty($classParts))
|
||||
{
|
||||
//found
|
||||
foreach (self::$namespaces[$namespace] as $namespaceLocation)
|
||||
//go from the end
|
||||
$namespace = implode("\\", $classParts) . "\\";
|
||||
|
||||
if (isset(self::$namespaces[$namespace]))
|
||||
{
|
||||
$depth = $namespaceLocation["depth"];
|
||||
$path = $namespaceLocation["path"];
|
||||
|
||||
$fileParts = explode("\\", $classInfo["real"]);
|
||||
|
||||
for ($i = 0; $i <= $depth; $i++)
|
||||
//found
|
||||
foreach (self::$namespaces[$namespace] as $namespaceLocation)
|
||||
{
|
||||
array_shift($fileParts);
|
||||
}
|
||||
$depth = $namespaceLocation["depth"];
|
||||
$path = $namespaceLocation["path"];
|
||||
|
||||
$classPath = implode("/", $fileParts);
|
||||
$fileParts = explode("\\", $classInfo["real"]);
|
||||
|
||||
$classPathLower = strtolower($classPath);
|
||||
for ($i = 0; $i <= $depth; $i++)
|
||||
{
|
||||
array_shift($fileParts);
|
||||
}
|
||||
|
||||
// final path lower case
|
||||
$filePath = $path . '/' . $classPathLower . ".php";
|
||||
$classPath = implode("/", $fileParts);
|
||||
|
||||
if (file_exists($filePath))
|
||||
{
|
||||
require_once($filePath);
|
||||
break 3;
|
||||
}
|
||||
$classPathLower = strtolower($classPath);
|
||||
|
||||
// final path original case
|
||||
$filePath = $path . '/' . $classPath . ".php";
|
||||
// final path lower case
|
||||
$filePath = $path . '/' . $classPathLower . ".php";
|
||||
|
||||
if (file_exists($filePath))
|
||||
{
|
||||
require_once($filePath);
|
||||
break 3;
|
||||
if (file_exists($filePath))
|
||||
{
|
||||
require_once($filePath);
|
||||
break 3;
|
||||
}
|
||||
|
||||
// final path original case
|
||||
$filePath = $path . '/' . $classPath . ".php";
|
||||
|
||||
if (file_exists($filePath))
|
||||
{
|
||||
require_once($filePath);
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//try the shorter namespace
|
||||
array_pop($classParts);
|
||||
//try the shorter namespace
|
||||
array_pop($classParts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dynamically define the class aliases
|
||||
if (isset(self::$classAliases[$classLower]))
|
||||
{
|
||||
foreach (self::$classAliases[$classLower] as $alias)
|
||||
{
|
||||
class_exists($alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,6 +619,40 @@ class Loader
|
||||
{
|
||||
self::$requireThrowException = (bool)$requireThrowException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include autoload.php files from composer folder.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function includeComposerAutoload(): void
|
||||
{
|
||||
// load from config
|
||||
$composerSettings = Configuration::getValue('composer');
|
||||
if (empty($composerSettings['config_path']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$composerFilePath = (string)$composerSettings['config_path'];
|
||||
if ($composerFilePath[0] !== '/')
|
||||
{
|
||||
$composerFilePath = realpath(
|
||||
self::getDocumentRoot() . '/' . $composerFilePath
|
||||
);
|
||||
if (empty($composerFilePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
require_once dirname($composerFilePath) . '/vendor/autoload.php';
|
||||
}
|
||||
|
||||
public static function getNamespaces(): array
|
||||
{
|
||||
return self::$namespaces;
|
||||
}
|
||||
}
|
||||
|
||||
class LoaderException extends \Exception
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2012 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Mail;
|
||||
|
||||
use Bitrix\Main;
|
||||
use Bitrix\Main\Mail\Internal as MailInternal;
|
||||
use Bitrix\Main\Config as Config;
|
||||
use Bitrix\Main\Config;
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\ORM\Data\AddResult;
|
||||
|
||||
class Event
|
||||
{
|
||||
@@ -27,6 +29,11 @@ class Event
|
||||
*/
|
||||
public static function sendImmediate(array $data)
|
||||
{
|
||||
if (!static::onBeforeEventAdd($data))
|
||||
{
|
||||
return static::SEND_RESULT_NONE;
|
||||
}
|
||||
|
||||
$data["ID"] = 0;
|
||||
|
||||
return static::handleEvent($data);
|
||||
@@ -36,21 +43,28 @@ class Event
|
||||
* Send mail event
|
||||
*
|
||||
* @param array $data Params of event
|
||||
* @return Main\Entity\AddResult
|
||||
* @return AddResult
|
||||
*/
|
||||
public static function send(array $data)
|
||||
{
|
||||
if (!static::onBeforeEventAdd($data))
|
||||
{
|
||||
return (new AddResult())->addError(new Main\Error('OnBeforeEventAdd'));
|
||||
}
|
||||
|
||||
$manageCache = Application::getInstance()->getManagedCache();
|
||||
if(CACHED_b_event !== false && $manageCache->read(CACHED_b_event, "events"))
|
||||
if (CACHED_b_event !== false && $manageCache->read(CACHED_b_event, "events"))
|
||||
{
|
||||
$manageCache->clean('events');
|
||||
}
|
||||
|
||||
$fileList = [];
|
||||
if(isset($data['FILE']))
|
||||
if (isset($data['FILE']))
|
||||
{
|
||||
if(is_array($data['FILE']))
|
||||
if (is_array($data['FILE']))
|
||||
{
|
||||
$fileList = $data['FILE'];
|
||||
}
|
||||
|
||||
unset($data['FILE']);
|
||||
}
|
||||
@@ -79,7 +93,7 @@ class Event
|
||||
|
||||
$connection->startTransaction();
|
||||
|
||||
$result = MailInternal\EventTable::add($data);
|
||||
$result = Internal\EventTable::add($data);
|
||||
|
||||
if ($result->isSuccess())
|
||||
{
|
||||
@@ -98,7 +112,7 @@ class Event
|
||||
$attachment['FILE_ID'] = \CFile::SaveFile($file['FILE'], 'main');
|
||||
}
|
||||
|
||||
MailInternal\EventAttachmentTable::add($attachment);
|
||||
Internal\EventAttachmentTable::add($attachment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,38 +121,76 @@ class Event
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function onBeforeEventAdd(array &$data): bool
|
||||
{
|
||||
foreach (GetModuleEvents("main", "OnBeforeEventAdd", true) as $arEvent)
|
||||
{
|
||||
if (ExecuteModuleEventEx($arEvent, [&$data["EVENT_NAME"], &$data["LID"], &$data["C_FIELDS"], &$data["MESSAGE_ID"], &$data["FILE"], &$data["LANGUAGE_ID"]]) === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['LID']) && is_array($data['LID']))
|
||||
{
|
||||
$data['LID'] = implode(",", $data['LID']);
|
||||
}
|
||||
|
||||
if (!is_array($data["C_FIELDS"] ?? null))
|
||||
{
|
||||
$data["C_FIELDS"] = [];
|
||||
}
|
||||
|
||||
if (isset($data["MESSAGE_ID"]) && (int)$data["MESSAGE_ID"] > 0)
|
||||
{
|
||||
$data["MESSAGE_ID"] = (int)$data["MESSAGE_ID"];
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($data["MESSAGE_ID"]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arEvent
|
||||
* @return string
|
||||
* @throws Main\ArgumentException
|
||||
* @throws Main\ArgumentNullException
|
||||
* @throws Main\ArgumentTypeException
|
||||
*/
|
||||
public static function handleEvent(array $arEvent)
|
||||
{
|
||||
if(!isset($arEvent['FIELDS']) && isset($arEvent['C_FIELDS']))
|
||||
if (!isset($arEvent['FIELDS']) && isset($arEvent['C_FIELDS']))
|
||||
{
|
||||
$arEvent['FIELDS'] = $arEvent['C_FIELDS'];
|
||||
}
|
||||
|
||||
if(!is_array($arEvent['FIELDS']))
|
||||
throw new Main\ArgumentTypeException("FIELDS" );
|
||||
if (!is_array($arEvent['FIELDS']))
|
||||
{
|
||||
throw new Main\ArgumentTypeException("FIELDS");
|
||||
}
|
||||
|
||||
$flag = static::SEND_RESULT_TEMPLATE_NOT_FOUND; // no templates
|
||||
$arResult = array(
|
||||
$arResult = [
|
||||
"Success" => false,
|
||||
"Fail" => false,
|
||||
"Was" => false,
|
||||
"Skip" => false,
|
||||
);
|
||||
];
|
||||
|
||||
$trackRead = null;
|
||||
$trackClick = null;
|
||||
if(array_key_exists('TRACK_READ', $arEvent))
|
||||
if (array_key_exists('TRACK_READ', $arEvent))
|
||||
{
|
||||
$trackRead = $arEvent['TRACK_READ'];
|
||||
if(array_key_exists('TRACK_CLICK', $arEvent))
|
||||
}
|
||||
if (array_key_exists('TRACK_CLICK', $arEvent))
|
||||
{
|
||||
$trackClick = $arEvent['TRACK_CLICK'];
|
||||
}
|
||||
|
||||
$arSites = explode(",", $arEvent["LID"]);
|
||||
if(empty($arSites))
|
||||
if (empty($arSites))
|
||||
{
|
||||
return $flag;
|
||||
}
|
||||
@@ -148,76 +200,76 @@ class Event
|
||||
$charset = false;
|
||||
$serverName = null;
|
||||
|
||||
static $sites = array();
|
||||
static $sites = [];
|
||||
$infoSite = reset($arSites);
|
||||
|
||||
if(!isset($sites[$infoSite]))
|
||||
if (!isset($sites[$infoSite]))
|
||||
{
|
||||
$siteDb = Main\SiteTable::getList(array(
|
||||
'select' => array('SERVER_NAME', 'CULTURE_CHARSET'=>'CULTURE.CHARSET'),
|
||||
'filter' => array('=LID' => $infoSite)
|
||||
));
|
||||
$siteDb = Main\SiteTable::getList([
|
||||
'select' => ['SERVER_NAME', 'CULTURE_CHARSET' => 'CULTURE.CHARSET'],
|
||||
'filter' => ['=LID' => $infoSite],
|
||||
]);
|
||||
$sites[$infoSite] = $siteDb->fetch();
|
||||
}
|
||||
|
||||
if(is_array($sites[$infoSite]))
|
||||
if (is_array($sites[$infoSite]))
|
||||
{
|
||||
$charset = $sites[$infoSite]['CULTURE_CHARSET'];
|
||||
$serverName = $sites[$infoSite]['SERVER_NAME'];
|
||||
}
|
||||
|
||||
if(!$charset)
|
||||
if (!$charset)
|
||||
{
|
||||
return $flag;
|
||||
}
|
||||
|
||||
// get filter for list of message templates
|
||||
$arEventMessageFilter = array();
|
||||
$MESSAGE_ID = intval($arEvent["MESSAGE_ID"]);
|
||||
if($MESSAGE_ID > 0)
|
||||
$arEventMessageFilter = [];
|
||||
$MESSAGE_ID = intval($arEvent["MESSAGE_ID"] ?? 0);
|
||||
if ($MESSAGE_ID > 0)
|
||||
{
|
||||
$eventMessageDb = MailInternal\EventMessageTable::getById($MESSAGE_ID);
|
||||
if($eventMessageDb->Fetch())
|
||||
$eventMessageDb = Internal\EventMessageTable::getById($MESSAGE_ID);
|
||||
if ($eventMessageDb->Fetch())
|
||||
{
|
||||
$arEventMessageFilter['=ID'] = $MESSAGE_ID;
|
||||
$arEventMessageFilter['=ACTIVE'] = 'Y';
|
||||
}
|
||||
}
|
||||
if(empty($arEventMessageFilter))
|
||||
if (empty($arEventMessageFilter))
|
||||
{
|
||||
$arEventMessageFilter = array(
|
||||
$arEventMessageFilter = [
|
||||
'=ACTIVE' => 'Y',
|
||||
'=EVENT_NAME' => $arEvent["EVENT_NAME"],
|
||||
'=EVENT_MESSAGE_SITE.SITE_ID' => $arSites,
|
||||
);
|
||||
];
|
||||
|
||||
if($arEvent["LANGUAGE_ID"] <> '')
|
||||
if ($arEvent["LANGUAGE_ID"] <> '')
|
||||
{
|
||||
$arEventMessageFilter[] = array(
|
||||
$arEventMessageFilter[] = [
|
||||
"LOGIC" => "OR",
|
||||
array("=LANGUAGE_ID" => $arEvent["LANGUAGE_ID"]),
|
||||
array("=LANGUAGE_ID" => null),
|
||||
);
|
||||
["=LANGUAGE_ID" => $arEvent["LANGUAGE_ID"]],
|
||||
["=LANGUAGE_ID" => null],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// get list of message templates of event
|
||||
$messageDb = MailInternal\EventMessageTable::getList(array(
|
||||
'select' => array('ID'),
|
||||
$messageDb = Internal\EventMessageTable::getList([
|
||||
'select' => ['ID'],
|
||||
'filter' => $arEventMessageFilter,
|
||||
'group' => array('ID')
|
||||
));
|
||||
'group' => ['ID'],
|
||||
]);
|
||||
|
||||
while($arMessage = $messageDb->fetch())
|
||||
while ($arMessage = $messageDb->fetch())
|
||||
{
|
||||
$eventMessage = MailInternal\EventMessageTable::getRowById($arMessage['ID']);
|
||||
$eventMessage = Internal\EventMessageTable::getRowById($arMessage['ID']);
|
||||
|
||||
$eventMessage['FILE'] = array();
|
||||
$attachmentDb = MailInternal\EventMessageAttachmentTable::getList(array(
|
||||
'select' => array('FILE_ID'),
|
||||
'filter' => array('=EVENT_MESSAGE_ID' => $arMessage['ID']),
|
||||
));
|
||||
while($arAttachmentDb = $attachmentDb->fetch())
|
||||
$eventMessage['FILE'] = [];
|
||||
$attachmentDb = Internal\EventMessageAttachmentTable::getList([
|
||||
'select' => ['FILE_ID'],
|
||||
'filter' => ['=EVENT_MESSAGE_ID' => $arMessage['ID']],
|
||||
]);
|
||||
while ($arAttachmentDb = $attachmentDb->fetch())
|
||||
{
|
||||
$eventMessage['FILE'][] = $arAttachmentDb['FILE_ID'];
|
||||
}
|
||||
@@ -227,26 +279,26 @@ class Event
|
||||
|
||||
foreach (GetModuleEvents("main", "OnBeforeEventSend", true) as $event)
|
||||
{
|
||||
if(ExecuteModuleEventEx($event, array(&$arFields, &$eventMessage, $context, &$arResult)) === false)
|
||||
if (ExecuteModuleEventEx($event, [&$arFields, &$eventMessage, $context, &$arResult]) === false)
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// get message object for send mail
|
||||
$arMessageParams = array(
|
||||
$arMessageParams = [
|
||||
'EVENT' => $arEvent,
|
||||
'FIELDS' => $arFields,
|
||||
'MESSAGE' => $eventMessage,
|
||||
'SITE' => $arSites,
|
||||
'CHARSET' => $charset,
|
||||
);
|
||||
];
|
||||
$message = EventMessageCompiler::createInstance($arMessageParams);
|
||||
try
|
||||
{
|
||||
$message->compile();
|
||||
}
|
||||
catch(StopException $e)
|
||||
catch (StopException)
|
||||
{
|
||||
$arResult["Was"] = true;
|
||||
$arResult["Fail"] = true;
|
||||
@@ -254,7 +306,7 @@ class Event
|
||||
}
|
||||
|
||||
// send mail
|
||||
$result = Main\Mail\Mail::send(array(
|
||||
$result = Main\Mail\Mail::send([
|
||||
'TO' => $message->getMailTo(),
|
||||
'SUBJECT' => $message->getMailSubject(),
|
||||
'BODY' => $message->getMailBody(),
|
||||
@@ -265,36 +317,50 @@ class Event
|
||||
'ATTACHMENT' => $message->getMailAttachment(),
|
||||
'TRACK_READ' => $trackRead,
|
||||
'TRACK_CLICK' => $trackClick,
|
||||
'LINK_PROTOCOL' => Config\Option::get("main", "mail_link_protocol", ''),
|
||||
'LINK_PROTOCOL' => Config\Option::get("main", "mail_link_protocol"),
|
||||
'LINK_DOMAIN' => $serverName,
|
||||
'CONTEXT' => $context,
|
||||
));
|
||||
if($result)
|
||||
]);
|
||||
if ($result)
|
||||
{
|
||||
$arResult["Success"] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$arResult["Fail"] = true;
|
||||
}
|
||||
|
||||
$arResult["Was"] = true;
|
||||
}
|
||||
|
||||
if($arResult["Was"])
|
||||
if ($arResult["Was"])
|
||||
{
|
||||
if($arResult["Success"])
|
||||
if ($arResult["Success"])
|
||||
{
|
||||
if($arResult["Fail"])
|
||||
$flag = static::SEND_RESULT_PARTLY; // partly sent
|
||||
if ($arResult["Fail"])
|
||||
{
|
||||
// partly sent
|
||||
$flag = static::SEND_RESULT_PARTLY;
|
||||
}
|
||||
else
|
||||
$flag = static::SEND_RESULT_SUCCESS; // all sent
|
||||
{
|
||||
// all sent
|
||||
$flag = static::SEND_RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($arResult["Fail"])
|
||||
$flag = static::SEND_RESULT_ERROR; // all templates failed
|
||||
if ($arResult["Fail"])
|
||||
{
|
||||
// all templates failed
|
||||
$flag = static::SEND_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($arResult["Skip"])
|
||||
elseif ($arResult["Skip"])
|
||||
{
|
||||
$flag = static::SEND_RESULT_NONE; // skip this event
|
||||
// skip this event
|
||||
$flag = static::SEND_RESULT_NONE;
|
||||
}
|
||||
|
||||
return $flag;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Type\DateTime;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
/**
|
||||
* Class BlacklistTable
|
||||
@@ -24,7 +24,7 @@ use Bitrix\Main\Type\DateTime;
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_Blacklist wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_Blacklist_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class BlacklistTable extends Entity\DataManager
|
||||
class BlacklistTable extends DataManager
|
||||
{
|
||||
const CategoryAuto = 0;
|
||||
const CategoryManual = 1;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2012 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Fields\ArrayField;
|
||||
use Bitrix\Main\Type as Type;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields\StringField;
|
||||
|
||||
/**
|
||||
* Class EventTable
|
||||
@@ -27,7 +30,7 @@ use Bitrix\Main\Type as Type;
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_Event wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_Event_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class EventTable extends Entity\DataManager
|
||||
class EventTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
@@ -107,7 +110,7 @@ class EventTable extends Entity\DataManager
|
||||
{
|
||||
return array(
|
||||
array(__CLASS__, "getFetchModificationForFieldsField"),
|
||||
array(new Entity\StringField('FIELDS', array()), "unserialize")
|
||||
array(new StringField('FIELDS', array()), "unserialize")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -198,7 +201,7 @@ class EventTable extends Entity\DataManager
|
||||
$newar[$key] = $val;
|
||||
}
|
||||
|
||||
$field = new Entity\StringField('FIELDS', array());
|
||||
$field = new StringField('FIELDS', array());
|
||||
return $field->serialize($newar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2012 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
/**
|
||||
* Class EventAttachmentTable
|
||||
@@ -26,7 +26,7 @@ use Bitrix\Main\Entity;
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_EventAttachment wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_EventAttachment_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class EventAttachmentTable extends Entity\DataManager
|
||||
class EventAttachmentTable extends DataManager
|
||||
{
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2012 Bitrix
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Orm;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Type as Type;
|
||||
use Bitrix\Main\Type;
|
||||
use Bitrix\Main\ORM;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields\ArrayField;
|
||||
|
||||
/**
|
||||
* Class EventMessageTable
|
||||
@@ -28,7 +30,7 @@ use Bitrix\Main\Type as Type;
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_EventMessage wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_EventMessage_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class EventMessageTable extends Entity\DataManager
|
||||
class EventMessageTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
@@ -52,7 +54,9 @@ class EventMessageTable extends Entity\DataManager
|
||||
'TIMESTAMP_X' => array(
|
||||
'data_type' => 'datetime',
|
||||
'required' => true,
|
||||
'default_value' => function(){return new Type\DateTime();},
|
||||
'default_value' => function() {
|
||||
return new Type\DateTime();
|
||||
},
|
||||
),
|
||||
'EVENT_NAME' => array(
|
||||
'data_type' => 'string',
|
||||
@@ -120,7 +124,7 @@ class EventMessageTable extends Entity\DataManager
|
||||
'SITE_TEMPLATE_ID' => array(
|
||||
'data_type' => 'string',
|
||||
),
|
||||
(new Orm\Fields\ArrayField('ADDITIONAL_FIELD'))->configureSerializationPhp(),
|
||||
(new ArrayField('ADDITIONAL_FIELD'))->configureSerializationPhp(),
|
||||
'EVENT_MESSAGE_SITE' => array(
|
||||
'data_type' => 'Bitrix\Main\Mail\Internal\EventMessageSite',
|
||||
'reference' => array('=this.ID' => 'ref.EVENT_MESSAGE_ID'),
|
||||
@@ -217,19 +221,19 @@ class EventMessageTable extends Entity\DataManager
|
||||
if(!empty($arReplaceTagsOne))
|
||||
$strResult = str_replace(array_keys($arReplaceTagsOne), array_values($arReplaceTagsOne), $strResult);
|
||||
|
||||
// php parser delete newline folowing the closing tag in string passed to eval
|
||||
// php parser delete newline following the closing tag in string passed to eval
|
||||
$strResult = str_replace(array("?>\n", "?>\r\n"), array("?>\n\n", "?>\r\n\r\n"), $strResult);
|
||||
|
||||
return $strResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Event $event
|
||||
* @return Entity\EventResult
|
||||
* @param ORM\Event $event
|
||||
* @return ORM\EventResult
|
||||
*/
|
||||
public static function onBeforeUpdate(Entity\Event $event)
|
||||
public static function onBeforeUpdate(ORM\Event $event)
|
||||
{
|
||||
$result = new Entity\EventResult;
|
||||
$result = new ORM\EventResult();
|
||||
$data = $event->getParameters();
|
||||
|
||||
if(array_key_exists('MESSAGE', $data['fields']))
|
||||
@@ -242,12 +246,12 @@ class EventMessageTable extends Entity\DataManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entity\Event $event
|
||||
* @return Entity\EventResult
|
||||
* @param ORM\Event $event
|
||||
* @return ORM\EventResult
|
||||
*/
|
||||
public static function onBeforeAdd(Entity\Event $event)
|
||||
public static function onBeforeAdd(ORM\Event $event)
|
||||
{
|
||||
$result = new Entity\EventResult;
|
||||
$result = new ORM\EventResult();
|
||||
$data = $event->getParameters();
|
||||
|
||||
if(array_key_exists('MESSAGE', $data['fields']))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
@@ -8,7 +9,7 @@
|
||||
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
/**
|
||||
* Class EventMessageAttachmentTable
|
||||
@@ -26,7 +27,7 @@ use Bitrix\Main\Entity;
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_EventMessageAttachment wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_EventMessageAttachment_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class EventMessageAttachmentTable extends Entity\DataManager
|
||||
class EventMessageAttachmentTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
@@ -53,5 +54,4 @@ class EventMessageAttachmentTable extends Entity\DataManager
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
/**
|
||||
* Class SenderSendCounterTable
|
||||
@@ -25,7 +25,7 @@ use Bitrix\Main\Entity;
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_SenderSendCounter wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_SenderSendCounter_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class SenderSendCounterTable extends Entity\DataManager
|
||||
class SenderSendCounterTable extends DataManager
|
||||
{
|
||||
public static function getTableName()
|
||||
{
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Bitrix\Main\Mail\Internal;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Config;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\Security;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
/**
|
||||
* Class SenderTable
|
||||
@@ -25,9 +25,8 @@ use Bitrix\Main\ORM\Fields;
|
||||
* @method static \Bitrix\Main\Mail\Internal\Sender wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Mail\Internal\EO_Sender_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class SenderTable extends Entity\DataManager
|
||||
class SenderTable extends DataManager
|
||||
{
|
||||
|
||||
public static function getTableName()
|
||||
{
|
||||
return 'b_main_mail_sender';
|
||||
@@ -42,7 +41,6 @@ class SenderTable extends Entity\DataManager
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public static function getObjectClass()
|
||||
{
|
||||
return Sender::class;
|
||||
@@ -163,5 +161,4 @@ class SenderTable extends Entity\DataManager
|
||||
->configureNullable(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
namespace Bitrix\Main\Mail;
|
||||
|
||||
use Bitrix\Main\Type;
|
||||
use Bitrix\Main\ORM\Fields\ExpressionField;
|
||||
use Bitrix\Main\DB\SqlExpression;
|
||||
|
||||
class SenderSendCounter
|
||||
{
|
||||
@@ -50,9 +52,9 @@ class SenderSendCounter
|
||||
$counter = 0;
|
||||
$date = new Type\Date(date("01.m.Y"), "d.m.Y");
|
||||
|
||||
$res = Internals\SenderSendCounterTable::getList(array(
|
||||
$res = Internal\SenderSendCounterTable::getList(array(
|
||||
"select" => array(
|
||||
new \Bitrix\Main\Entity\ExpressionField('CNT', 'SUM(CNT)'),
|
||||
new ExpressionField('CNT', 'SUM(CNT)'),
|
||||
),
|
||||
"filter" => array(
|
||||
">=DATE_STAT" => $date,
|
||||
@@ -80,7 +82,7 @@ class SenderSendCounter
|
||||
"CNT" => $increment,
|
||||
);
|
||||
$update = array(
|
||||
"CNT" => new \Bitrix\Main\DB\SqlExpression("?# + ?i", "CNT", $increment),
|
||||
"CNT" => new SqlExpression("?# + ?i", "CNT", $increment),
|
||||
);
|
||||
|
||||
Internal\SenderSendCounterTable::mergeData($insert, $update);
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
namespace Bitrix\Main\Numerator\Model;
|
||||
|
||||
use Bitrix\Main\Entity\DataManager;
|
||||
use Bitrix\Main\Entity\DatetimeField;
|
||||
use Bitrix\Main\Entity\IntegerField;
|
||||
use Bitrix\Main\Entity\StringField;
|
||||
use Bitrix\Main\Entity\UpdateResult;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields\DatetimeField;
|
||||
use Bitrix\Main\ORM\Fields\IntegerField;
|
||||
use Bitrix\Main\ORM\Fields\StringField;
|
||||
use Bitrix\Main\ORM\Data\UpdateResult;
|
||||
use Bitrix\Main\ORM\Data\AddResult;
|
||||
use Bitrix\Main\Error;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\Numerator\Generator\Contract\Sequenceable;
|
||||
@@ -160,7 +161,7 @@ class NumeratorTable extends DataManager
|
||||
/**
|
||||
* @param $numeratorId
|
||||
* @param $numeratorFields
|
||||
* @return \Bitrix\Main\Entity\AddResult|UpdateResult
|
||||
* @return AddResult|UpdateResult
|
||||
* @throws SystemException
|
||||
* @throws \Bitrix\Main\ArgumentException
|
||||
* @throws \Bitrix\Main\ObjectException
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Numerator\Model;
|
||||
|
||||
use Bitrix\Main\DB\SqlQueryException;
|
||||
use Bitrix\Main\Entity\DataManager;
|
||||
use Bitrix\Main\Entity\IntegerField;
|
||||
use Bitrix\Main\Entity\StringField;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields\IntegerField;
|
||||
use Bitrix\Main\ORM\Fields\StringField;
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\Result;
|
||||
|
||||
@@ -172,4 +173,4 @@ class NumeratorSequenceTable extends DataManager
|
||||
throw $exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\Numerator;
|
||||
|
||||
use Bitrix\Main\Entity\ExpressionField;
|
||||
use Bitrix\Main\Entity\Query;
|
||||
use Bitrix\Main\ORM\Fields\ExpressionField;
|
||||
use Bitrix\Main\ORM\Query\Query;
|
||||
use Bitrix\Main\Error;
|
||||
use Bitrix\Main\Event;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
@@ -268,7 +268,7 @@ class Numerator
|
||||
/**
|
||||
* @param $numId
|
||||
* @param $config - same configuration structure as using via setConfig method
|
||||
* @return \Bitrix\Main\Entity\AddResult|\Bitrix\Main\Entity\UpdateResult|Result
|
||||
* @return \Bitrix\Main\ORM\Data\AddResult|\Bitrix\Main\ORM\Data\UpdateResult|Result
|
||||
* @throws \Bitrix\Main\ArgumentException
|
||||
* @throws \Bitrix\Main\NotImplementedException
|
||||
* @throws \Bitrix\Main\ObjectException
|
||||
@@ -315,7 +315,7 @@ class Numerator
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Bitrix\Main\Entity\AddResult|\Bitrix\Main\Entity\UpdateResult
|
||||
* @return \Bitrix\Main\ORM\Data\AddResult|\Bitrix\Main\ORM\Data\UpdateResult
|
||||
* @throws \Bitrix\Main\ArgumentException
|
||||
* @throws \Bitrix\Main\ObjectException
|
||||
* @throws \Bitrix\Main\ObjectPropertyException
|
||||
@@ -400,7 +400,7 @@ class Numerator
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return $this|\Bitrix\Main\Entity\DeleteResult|Result
|
||||
* @return $this|\Bitrix\Main\ORM\Data\DeleteResult|Result
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function delete($id)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
namespace Bitrix\Main\Numerator\Service;
|
||||
|
||||
use Bitrix\Main\Entity\ReferenceField;
|
||||
use Bitrix\Main\ORM\Fields\Relations\Reference;
|
||||
use Bitrix\Main\ORM\Data;
|
||||
use Bitrix\Main\Error;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\Numerator\Generator\SequentNumberGenerator;
|
||||
@@ -29,7 +30,7 @@ class NumeratorRequestManager
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Bitrix\Main\Entity\AddResult|\Bitrix\Main\Entity\UpdateResult|Result
|
||||
* @return Data\AddResult|Data\UpdateResult|Result
|
||||
* @throws \Bitrix\Main\ArgumentException
|
||||
* @throws \Bitrix\Main\NotImplementedException
|
||||
* @throws \Bitrix\Main\ObjectException
|
||||
@@ -79,7 +80,7 @@ class NumeratorRequestManager
|
||||
{
|
||||
$sequence = NumeratorTable::query()
|
||||
->registerRuntimeField('',
|
||||
new ReferenceField(
|
||||
new Reference(
|
||||
'ref',
|
||||
NumeratorSequenceTable::class,
|
||||
['=this.ID' => 'ref.NUMERATOR_ID']
|
||||
|
||||
@@ -183,7 +183,7 @@ abstract class Collection implements \ArrayAccess, \Iterator, \Countable
|
||||
/**
|
||||
* @param $primary
|
||||
*
|
||||
* @return EntityObject
|
||||
* @return EntityObject|null
|
||||
* @throws ArgumentException
|
||||
*/
|
||||
final public function getByPrimary($primary)
|
||||
|
||||
@@ -1905,7 +1905,7 @@ abstract class EntityObject implements ArrayAccess
|
||||
{
|
||||
$fieldName = StringHelper::strtoupper($fieldName);
|
||||
|
||||
if (!isset($this->_actualValues[$fieldName]))
|
||||
if (!array_key_exists($fieldName, $this->_actualValues))
|
||||
{
|
||||
// regular field
|
||||
$list[] = $fieldName;
|
||||
@@ -1937,7 +1937,8 @@ abstract class EntityObject implements ArrayAccess
|
||||
{
|
||||
$fieldMask = $field->getTypeMask();
|
||||
|
||||
if (!isset($this->_actualValues[StringHelper::strtoupper($field->getName())])
|
||||
if (
|
||||
!array_key_exists(StringHelper::strtoupper($field->getName()), $this->_actualValues)
|
||||
&& ($mask & $fieldMask)
|
||||
)
|
||||
{
|
||||
|
||||
@@ -181,7 +181,7 @@ class Expression
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getTmpName($postfix)
|
||||
public static function getTmpName($postfix)
|
||||
{
|
||||
return 'A'.strtoupper(Random::getString(6).'_'.$postfix);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,14 @@ class Condition
|
||||
*/
|
||||
public function getDefinition()
|
||||
{
|
||||
return $this->getColumn();
|
||||
$definition = $this->getColumn();
|
||||
|
||||
if ($definition instanceof ColumnExpression)
|
||||
{
|
||||
$definition = $definition->getDefinition();
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -105,11 +105,22 @@ class QueryHelper
|
||||
// original sort
|
||||
if (!empty($rows))
|
||||
{
|
||||
/**
|
||||
* @var \Bitrix\Main\ORM\Objectify\Collection $sortedCollection
|
||||
*/
|
||||
$sortedCollection = $query->getEntity()->createCollection();
|
||||
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$sortedCollection->add($collection->getByPrimary($row));
|
||||
$collectionItem = $collection->getByPrimary($row);
|
||||
if ($collectionItem)
|
||||
{
|
||||
$sortedCollection->add($collectionItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('Phantom reading', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
$collection = $sortedCollection;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Bitrix\Main\Service\GeoIp;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields\Validators\LengthValidator;
|
||||
|
||||
/**
|
||||
* Class HandlerTable
|
||||
@@ -33,7 +34,7 @@ use Bitrix\Main\Localization\Loc;
|
||||
* @method static \Bitrix\Main\Service\GeoIp\EO_Handler_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
|
||||
class HandlerTable extends Entity\DataManager
|
||||
class HandlerTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* Returns DB table name for entity.
|
||||
@@ -90,7 +91,7 @@ class HandlerTable extends Entity\DataManager
|
||||
public static function validateClassName()
|
||||
{
|
||||
return array(
|
||||
new Entity\Validator\Length(null, 255),
|
||||
new LengthValidator(null, 255),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<?php
|
||||
namespace Bitrix\Main\Session\Handlers\Table;
|
||||
|
||||
namespace Bitrix\Main\Session\Handlers\Table;
|
||||
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\DB\MysqlCommonConnection;
|
||||
use Bitrix\Main\DB\PgsqlConnection;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Type;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
|
||||
/**
|
||||
* Class UserSessionTable
|
||||
@@ -24,7 +25,7 @@ use Bitrix\Main\Type;
|
||||
* @method static \Bitrix\Main\Session\Handlers\Table\EO_UserSession wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Session\Handlers\Table\EO_UserSession_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class UserSessionTable extends Entity\DataManager
|
||||
class UserSessionTable extends DataManager
|
||||
{
|
||||
/** @var string Connection name used for SQL queries */
|
||||
public const CONNECTION_NAME = 'user_session';
|
||||
@@ -41,7 +42,7 @@ class UserSessionTable extends Entity\DataManager
|
||||
|
||||
/**
|
||||
* Returns connection name for entity
|
||||
* Have side affect, keep it in mind!
|
||||
* Has side effect, keep it in mind!
|
||||
* Clone default database connection if connection {@link SessionTable::CONNECTION_NAME} doesn't exists
|
||||
*
|
||||
* @return string
|
||||
@@ -69,14 +70,14 @@ class UserSessionTable extends Entity\DataManager
|
||||
public static function getMap()
|
||||
{
|
||||
return [
|
||||
new Entity\StringField('SESSION_ID', [
|
||||
new Fields\StringField('SESSION_ID', [
|
||||
'primary' => true,
|
||||
'format' => '#^[0-9a-z\-,]{6,250}$#iD'
|
||||
]),
|
||||
new Entity\DatetimeField('TIMESTAMP_X', [
|
||||
new Fields\DatetimeField('TIMESTAMP_X', [
|
||||
'default_value' => new Type\DateTime
|
||||
]),
|
||||
new Entity\TextField('SESSION_DATA', [
|
||||
new Fields\TextField('SESSION_DATA', [
|
||||
'default_value' => '',
|
||||
'save_data_modification' => function() {
|
||||
return [
|
||||
|
||||
@@ -50,13 +50,17 @@ class StringHelper
|
||||
* Changes registry from snake_case or SNAKE_CASE to CamelCase
|
||||
*
|
||||
* @param $str
|
||||
*
|
||||
* @param bool $lowCaseFirst
|
||||
* @return mixed
|
||||
*/
|
||||
public static function snake2camel($str)
|
||||
public static function snake2camel($str, bool $lowCaseFirst = false)
|
||||
{
|
||||
$str = str_replace('_', ' ', mb_strtolower($str));
|
||||
return str_replace(' ', '', ucwords($str));
|
||||
$str = str_replace(' ', '', ucwords($str));
|
||||
|
||||
return $lowCaseFirst
|
||||
? lcfirst($str)
|
||||
: $str;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -797,12 +797,6 @@ In addition to the Google Terms of Service (http://www.google.com/accounts/TOS),
|
||||
->setCopyright("Copyright 2012 The Apache Software Foundation")
|
||||
->setLicence(static::LICENCE_APACHE2),
|
||||
|
||||
// faceid/install/components/bitrix/faceid.tracker/templates/.default/smoother.js
|
||||
// faceid/install/js/faceid/WebPhotoMaker/smoother.js
|
||||
(new static("Smoother"))
|
||||
->setCopyright("Copyright 2014 Martin Tschirsich")
|
||||
->setLicence(static::LICENCE_MIT),
|
||||
|
||||
// ui/install/js/ui/fonts/comforter-brush
|
||||
(new static("Font Comforter Brush"))
|
||||
->setCopyright("Copyright 2015 The Comforter Brush Project Authors")
|
||||
@@ -862,6 +856,32 @@ In addition to the Google Terms of Service (http://www.google.com/accounts/TOS),
|
||||
->setProductUrl('https://github.com/simshaun/recurr')
|
||||
->setLicence(static::LICENCE_MIT)
|
||||
->setLicenceUrl('https://github.com/simshaun/recurr/blob/master/LICENSE'),
|
||||
|
||||
// mobile/install/mobileapp/mobile/extensions/bitrix/statemanager/redux
|
||||
(new static('Redux Toolkit'))
|
||||
->setCopyright('Copyright (c) 2018 Mark Erikson')
|
||||
->setProductUrl('https://redux-toolkit.js.org')
|
||||
->setLicence(Copyright::LICENCE_MIT),
|
||||
|
||||
(new static('Redux-State-Sync 3'))
|
||||
->setCopyright('Copyright (c) 2018 MU AOHUA')
|
||||
->setProductUrl('https://github.com/AOHUA/redux-state-sync')
|
||||
->setLicence(Copyright::LICENCE_MIT),
|
||||
|
||||
(new static('Logger for Redux'))
|
||||
->setCopyright('Copyright (c) 2016 Eugene Rodionov')
|
||||
->setProductUrl('https://github.com/LogRocket/redux-logger')
|
||||
->setLicence(Copyright::LICENCE_MIT),
|
||||
|
||||
(new static('redux-batched-subscribe'))
|
||||
->setCopyright('Copyright (c) 2016 Terry Appleby')
|
||||
->setProductUrl('https://github.com/tappleby/redux-batched-subscribe')
|
||||
->setLicence(Copyright::LICENCE_MIT),
|
||||
|
||||
(new static('redux-batched-actions'))
|
||||
->setCopyright('Copyright (c) 2016 Tim Shelburne')
|
||||
->setProductUrl('https://github.com/tshelburne/redux-batched-actions')
|
||||
->setLicence(Copyright::LICENCE_MIT),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,11 +54,14 @@ class PageNavigation
|
||||
|
||||
if(($value = $request->getQuery($this->id)) !== null)
|
||||
{
|
||||
//parameters are in the QUERY_STRING
|
||||
$params = explode("-", $value);
|
||||
for($i = 0, $n = count($params); $i < $n; $i += 2)
|
||||
if (is_string($value))
|
||||
{
|
||||
$navParams[$params[$i]] = $params[$i+1];
|
||||
//parameters are in the QUERY_STRING
|
||||
$params = explode("-", $value);
|
||||
for($i = 0, $n = count($params); $i < $n; $i += 2)
|
||||
{
|
||||
$navParams[$params[$i]] = $params[$i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -8,6 +8,7 @@ use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ModuleManager;
|
||||
use Bitrix\Main\FinderDestTable;
|
||||
use Bitrix\Main\Loader;
|
||||
use Bitrix\Main\ORM\Fields\ExpressionField;
|
||||
|
||||
class Entities
|
||||
{
|
||||
@@ -281,6 +282,8 @@ class Entities
|
||||
|
||||
public static function getLastSort($params = array())
|
||||
{
|
||||
global $USER;
|
||||
|
||||
$result = array(
|
||||
'DATA' => array(),
|
||||
'DATA_ADDITIONAL' => array()
|
||||
@@ -392,7 +395,7 @@ class Entities
|
||||
$helper = $conn->getSqlHelper();
|
||||
|
||||
$runtime = array(
|
||||
new \Bitrix\Main\Entity\ExpressionField('CONTEXT_SORT', "CASE WHEN CONTEXT = '".$helper->forSql(mb_strtoupper($params["DEST_CONTEXT"]))."' THEN 1 ELSE 0 END")
|
||||
new ExpressionField('CONTEXT_SORT', "CASE WHEN CONTEXT = '".$helper->forSql(mb_strtoupper($params["DEST_CONTEXT"]))."' THEN 1 ELSE 0 END")
|
||||
);
|
||||
|
||||
$order = array(
|
||||
@@ -767,7 +770,7 @@ class Entities
|
||||
{
|
||||
$selectList[] = 'UF_USER_CRM_ENTITY';
|
||||
}
|
||||
$selectList[] = new \Bitrix\Main\Entity\ExpressionField('MAX_LAST_USE_DATE', 'MAX(%s)', array('\Bitrix\Main\FinderDest:CODE_USER_CURRENT.LAST_USE_DATE'));
|
||||
$selectList[] = new ExpressionField('MAX_LAST_USE_DATE', 'MAX(%s)', array('\Bitrix\Main\FinderDest:CODE_USER_CURRENT.LAST_USE_DATE'));
|
||||
|
||||
$res = \Bitrix\Main\UserTable::getList(array(
|
||||
'order' => array(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Main\UI\Viewer;
|
||||
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
use Bitrix\Main\FileTable;
|
||||
use Bitrix\Main\ORM\Event;
|
||||
use Bitrix\Main\Type\Date;
|
||||
@@ -42,41 +42,43 @@ final class FilePreviewTable extends DataManager
|
||||
|
||||
/**
|
||||
* Returns entity map definition.
|
||||
* To get initialized fields @see \Bitrix\Main\Entity\Base::getFields() and \Bitrix\Main\Entity\Base::getField()
|
||||
* To get initialized fields
|
||||
* @return array
|
||||
* @throws \Bitrix\Main\SystemException
|
||||
* @see \Bitrix\Main\ORM\Entity::getFields()
|
||||
* @see \Bitrix\Main\ORM\Entity::getField()
|
||||
*/
|
||||
public static function getMap()
|
||||
{
|
||||
return [
|
||||
new Entity\IntegerField('ID', [
|
||||
new Fields\IntegerField('ID', [
|
||||
'primary' => true,
|
||||
'autocomplete' => true,
|
||||
]),
|
||||
new Entity\IntegerField('FILE_ID', [
|
||||
new Fields\IntegerField('FILE_ID', [
|
||||
'required' => true,
|
||||
]),
|
||||
new Entity\IntegerField('PREVIEW_ID'),
|
||||
new Entity\IntegerField('PREVIEW_IMAGE_ID'),
|
||||
new Entity\DatetimeField('CREATED_AT', [
|
||||
new Fields\IntegerField('PREVIEW_ID'),
|
||||
new Fields\IntegerField('PREVIEW_IMAGE_ID'),
|
||||
new Fields\DatetimeField('CREATED_AT', [
|
||||
'default_value' => function () {
|
||||
return new DateTime();
|
||||
},
|
||||
]),
|
||||
new Entity\DatetimeField('TOUCHED_AT', [
|
||||
new Fields\DatetimeField('TOUCHED_AT', [
|
||||
'default_value' => function () {
|
||||
return new DateTime();
|
||||
},
|
||||
]),
|
||||
new Entity\ReferenceField('FILE',FileTable::class,
|
||||
new Fields\Relations\Reference('FILE',FileTable::class,
|
||||
['=this.FILE_ID' => 'ref.ID'],
|
||||
['join_type' => 'INNER']
|
||||
),
|
||||
new Entity\ReferenceField('PREVIEW',FileTable::class,
|
||||
new Fields\Relations\Reference('PREVIEW',FileTable::class,
|
||||
['=this.PREVIEW_ID' => 'ref.ID'],
|
||||
['join_type' => 'LEFT']
|
||||
),
|
||||
new Entity\ReferenceField('PREVIEW_IMAGE',FileTable::class,
|
||||
new Fields\Relations\Reference('PREVIEW_IMAGE',FileTable::class,
|
||||
['=this.PREVIEW_IMAGE_ID' => 'ref.ID'],
|
||||
['join_type' => 'LEFT']
|
||||
),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Bitrix\Main\Update;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
/**
|
||||
* Class VersionHistoryTable
|
||||
@@ -21,7 +21,7 @@ use Bitrix\Main\Entity;
|
||||
* @method static \Bitrix\Main\Update\EO_VersionHistory wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\Update\EO_VersionHistory_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class VersionHistoryTable extends Entity\DataManager
|
||||
class VersionHistoryTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* Returns DB table name for entity
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace Bitrix\Main\UrlPreview;
|
||||
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main;
|
||||
use Bitrix\Main\Entity\AddResult;
|
||||
use Bitrix\Main\Entity\ScalarField;
|
||||
use Bitrix\Main\ORM\Data\AddResult;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
|
||||
/**
|
||||
* Class RouteTable
|
||||
@@ -24,9 +24,8 @@ use Bitrix\Main\Entity\ScalarField;
|
||||
* @method static \Bitrix\Main\UrlPreview\EO_Route wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\UrlPreview\EO_Route_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class RouteTable extends Entity\DataManager
|
||||
class RouteTable extends DataManager
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns DB table name for entity
|
||||
*
|
||||
@@ -45,21 +44,21 @@ class RouteTable extends Entity\DataManager
|
||||
public static function getMap()
|
||||
{
|
||||
return array(
|
||||
'ID' => new Entity\IntegerField('ID', array(
|
||||
'ID' => new Fields\IntegerField('ID', array(
|
||||
'primary' => true,
|
||||
'autocomplete' => true,
|
||||
)),
|
||||
'ROUTE' => new Entity\StringField('ROUTE', array(
|
||||
'ROUTE' => new Fields\StringField('ROUTE', array(
|
||||
'required' => true,
|
||||
'unique' => true
|
||||
)),
|
||||
'MODULE' => new Entity\StringField('MODULE', array(
|
||||
'MODULE' => new Fields\StringField('MODULE', array(
|
||||
'required' => true,
|
||||
)),
|
||||
'CLASS' => new Entity\StringField('CLASS', array(
|
||||
'CLASS' => new Fields\StringField('CLASS', array(
|
||||
'required' => true,
|
||||
)),
|
||||
'PARAMETERS' => new Entity\TextField('PARAMETERS', array(
|
||||
'PARAMETERS' => new Fields\TextField('PARAMETERS', array(
|
||||
'serialized' => true,
|
||||
)),
|
||||
);
|
||||
@@ -99,7 +98,7 @@ class RouteTable extends Entity\DataManager
|
||||
// set fields with default values
|
||||
foreach (static::getEntity()->getFields() as $field)
|
||||
{
|
||||
if ($field instanceof ScalarField && !array_key_exists($field->getName(), $data))
|
||||
if ($field instanceof Fields\ScalarField && !array_key_exists($field->getName(), $data))
|
||||
{
|
||||
$defaultValue = $field->getDefaultValue();
|
||||
|
||||
@@ -157,4 +156,4 @@ class RouteTable extends Entity\DataManager
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
namespace Bitrix\Main\UrlPreview;
|
||||
|
||||
use Bitrix\Main;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Text\Emoji;
|
||||
use Bitrix\Main\ORM\Event;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
|
||||
/**
|
||||
* Class UrlMetadataTable
|
||||
@@ -23,7 +24,7 @@ use Bitrix\Main\ORM\Event;
|
||||
* @method static \Bitrix\Main\UrlPreview\EO_UrlMetadata wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\UrlPreview\EO_UrlMetadata_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class UrlMetadataTable extends Entity\DataManager
|
||||
class UrlMetadataTable extends DataManager
|
||||
{
|
||||
const TYPE_STATIC = 'S';
|
||||
const TYPE_DYNAMIC = 'D';
|
||||
@@ -48,37 +49,37 @@ class UrlMetadataTable extends Entity\DataManager
|
||||
public static function getMap()
|
||||
{
|
||||
return array(
|
||||
'ID' => new Entity\IntegerField('ID', array(
|
||||
'ID' => new Fields\IntegerField('ID', array(
|
||||
'primary' => true,
|
||||
'autocomplete' => true,
|
||||
)),
|
||||
'URL' => new Entity\StringField('URL', array(
|
||||
'URL' => new Fields\StringField('URL', array(
|
||||
'required' => true,
|
||||
)),
|
||||
'TYPE' => new Entity\StringField('TYPE', array(
|
||||
'TYPE' => new Fields\StringField('TYPE', array(
|
||||
'required' => true,
|
||||
)),
|
||||
'TITLE' => new Entity\StringField('TITLE', [
|
||||
'TITLE' => new Fields\StringField('TITLE', [
|
||||
'save_data_modification' => [Emoji::class, 'getSaveModificator'],
|
||||
'fetch_data_modification' => [Emoji::class, 'getFetchModificator'],
|
||||
]),
|
||||
'DESCRIPTION' => new Entity\TextField('DESCRIPTION', [
|
||||
'DESCRIPTION' => new Fields\TextField('DESCRIPTION', [
|
||||
'save_data_modification' => [Emoji::class, 'getSaveModificator'],
|
||||
'fetch_data_modification' => [Emoji::class, 'getFetchModificator'],
|
||||
]),
|
||||
'IMAGE_ID' => new Entity\IntegerField('IMAGE_ID'),
|
||||
'IMAGE' => new Entity\StringField('IMAGE'),
|
||||
'EMBED' => new Entity\TextField('EMBED', [
|
||||
'IMAGE_ID' => new Fields\IntegerField('IMAGE_ID'),
|
||||
'IMAGE' => new Fields\StringField('IMAGE'),
|
||||
'EMBED' => new Fields\TextField('EMBED', [
|
||||
'save_data_modification' => [Emoji::class, 'getSaveModificator'],
|
||||
'fetch_data_modification' => [Emoji::class, 'getFetchModificator'],
|
||||
]),
|
||||
'EXTRA' => new Entity\TextField('EXTRA', array(
|
||||
'EXTRA' => new Fields\TextField('EXTRA', array(
|
||||
'serialized' => true,
|
||||
)),
|
||||
'DATE_INSERT' => new Entity\DatetimeField('DATE_INSERT', array(
|
||||
'DATE_INSERT' => new Fields\DatetimeField('DATE_INSERT', array(
|
||||
'default_value' => new Main\Type\DateTime(),
|
||||
)),
|
||||
'DATE_EXPIRE' => new Entity\DatetimeField('DATE_EXPIRE')
|
||||
'DATE_EXPIRE' => new Fields\DatetimeField('DATE_EXPIRE')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
namespace Bitrix\Main\UserConsent\Internals;
|
||||
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Type\DateTime;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\Security\Random;
|
||||
use Bitrix\Main\UserConsent\Agreement;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Event;
|
||||
use Bitrix\Main\ORM\EventResult;
|
||||
|
||||
Loc::loadMessages(__FILE__);
|
||||
|
||||
@@ -32,7 +34,7 @@ Loc::loadMessages(__FILE__);
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_Agreement wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_Agreement_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class AgreementTable extends Entity\DataManager
|
||||
class AgreementTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* Get table name.
|
||||
@@ -120,15 +122,15 @@ class AgreementTable extends Entity\DataManager
|
||||
/**
|
||||
* After delete event handler.
|
||||
*
|
||||
* @param Entity\Event $event Event object.
|
||||
* @return Entity\EventResult
|
||||
* @param Event $event Event object.
|
||||
* @return EventResult
|
||||
*/
|
||||
public static function onAfterDelete(Entity\Event $event)
|
||||
public static function onAfterDelete(Event $event)
|
||||
{
|
||||
$result = new Entity\EventResult;
|
||||
$result = new EventResult;
|
||||
$data = $event->getParameters();
|
||||
|
||||
$sql = /** @lang MySQL */ "DELETE FROM " . ConsentTable::getTableName() . " WHERE AGREEMENT_ID = " . intval($data['primary']['ID']);
|
||||
$sql = "DELETE FROM " . ConsentTable::getTableName() . " WHERE AGREEMENT_ID = " . intval($data['primary']['ID']);
|
||||
Application::getConnection()->query($sql);
|
||||
|
||||
return $result;
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
*/
|
||||
namespace Bitrix\Main\UserConsent\Internals;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Fields\Relations\OneToMany;
|
||||
use Bitrix\Main\Type\DateTime;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
Loc::loadMessages(__FILE__);
|
||||
|
||||
@@ -30,7 +30,7 @@ Loc::loadMessages(__FILE__);
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_Consent wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_Consent_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class ConsentTable extends Entity\DataManager
|
||||
class ConsentTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* Get table name.
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
*/
|
||||
namespace Bitrix\Main\UserConsent\Internals;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
Loc::loadMessages(__FILE__);
|
||||
|
||||
@@ -28,7 +28,7 @@ Loc::loadMessages(__FILE__);
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_Field wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_Field_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class FieldTable extends Entity\DataManager
|
||||
class FieldTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* Get table name.
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
*/
|
||||
namespace Bitrix\Main\UserConsent\Internals;
|
||||
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ORM\Fields\Relations\Reference;
|
||||
use Bitrix\Main\ORM\Query\Join;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
|
||||
Loc::loadMessages(__FILE__);
|
||||
|
||||
@@ -30,7 +30,7 @@ Loc::loadMessages(__FILE__);
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_UserConsentItem wakeUpObject($row)
|
||||
* @method static \Bitrix\Main\UserConsent\Internals\EO_UserConsentItem_Collection wakeUpCollection($rows)
|
||||
*/
|
||||
class UserConsentItemTable extends Entity\DataManager
|
||||
class UserConsentItemTable extends DataManager
|
||||
{
|
||||
/**
|
||||
* Get table name.
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
namespace Bitrix\Main\UserField\Access\Permission;
|
||||
|
||||
use Bitrix\Main\Access\Permission\AccessPermissionTable;
|
||||
use Bitrix\Main\Entity;
|
||||
use Bitrix\Main\ORM\Fields;
|
||||
use Bitrix\Main\ORM\Query\Query;
|
||||
use Bitrix\Main\ORM\Query\Join;
|
||||
use Bitrix\Main\ORM\Fields\Relations\Reference;
|
||||
use Bitrix\Main\UserAccessTable;
|
||||
@@ -42,23 +43,23 @@ class UserFieldPermissionTable extends AccessPermissionTable
|
||||
public static function getMap()
|
||||
{
|
||||
return [
|
||||
new Entity\IntegerField('ID', [
|
||||
new Fields\IntegerField('ID', [
|
||||
'autocomplete' => true,
|
||||
'primary' => true
|
||||
]),
|
||||
new Entity\IntegerField('ENTITY_TYPE_ID', [
|
||||
new Fields\IntegerField('ENTITY_TYPE_ID', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\IntegerField('USER_FIELD_ID', [
|
||||
new Fields\IntegerField('USER_FIELD_ID', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\StringField('ACCESS_CODE', [
|
||||
new Fields\StringField('ACCESS_CODE', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\StringField('PERMISSION_ID', [
|
||||
new Fields\StringField('PERMISSION_ID', [
|
||||
'required' => true
|
||||
]),
|
||||
new Entity\IntegerField('VALUE', [
|
||||
new Fields\IntegerField('VALUE', [
|
||||
'required' => true
|
||||
]),
|
||||
(new Reference(
|
||||
@@ -131,7 +132,7 @@ class UserFieldPermissionTable extends AccessPermissionTable
|
||||
*/
|
||||
public static function getUserFieldsAccessCodes(int $entityTypeID): array
|
||||
{
|
||||
$query = new Entity\Query(self::getEntity());
|
||||
$query = new Query(self::getEntity());
|
||||
$query->addSelect('USER_FIELD.FIELD_NAME', 'FIELD_NAME');
|
||||
$query->addSelect('ACCESS_CODE');
|
||||
$query->addSelect('USER_ACCESS.USER_ID', 'USER_ID');
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Bitrix\Main\UserField\Internal;
|
||||
use Bitrix\Main\Application;
|
||||
use Bitrix\Main\DB\MssqlConnection;
|
||||
use Bitrix\Main\DB\SqlQueryException;
|
||||
use Bitrix\Main\Entity\Validator\RegExp;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ORM\Data\DataManager;
|
||||
use Bitrix\Main\ORM\Entity;
|
||||
@@ -18,6 +17,7 @@ use Bitrix\Main\ORM\Fields\Field;
|
||||
use Bitrix\Main\ORM\Fields\IntegerField;
|
||||
use Bitrix\Main\ORM\Fields\Relations\Reference;
|
||||
use Bitrix\Main\ORM\Fields\StringField;
|
||||
use Bitrix\Main\ORM\Fields\Validators\RegExpValidator;
|
||||
use Bitrix\Main\ORM\Query\Query;
|
||||
use Bitrix\Main\SystemException;
|
||||
use Bitrix\Main\Text\StringHelper;
|
||||
@@ -42,7 +42,7 @@ abstract class TypeDataManager extends DataManager
|
||||
->configureUnique()
|
||||
->configureSize(100)
|
||||
->configureFormat('/^[A-Z][A-Za-z0-9]*$/')
|
||||
->addValidator(new RegExp(
|
||||
->addValidator(new RegExpValidator(
|
||||
'/(?<!Table)$/i'
|
||||
)),
|
||||
(new StringField('TABLE_NAME'))
|
||||
@@ -546,4 +546,4 @@ abstract class TypeDataManager extends DataManager
|
||||
{
|
||||
return Type::class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
109
core/bitrix/modules/main/lib/web/http/range.php
Normal file
109
core/bitrix/modules/main/lib/web/http/range.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bitrix Framework
|
||||
* @package bitrix
|
||||
* @subpackage main
|
||||
* @copyright 2001-2025 Bitrix
|
||||
*/
|
||||
|
||||
namespace Bitrix\Main\Web\Http;
|
||||
|
||||
use Bitrix\Main\ArgumentException;
|
||||
|
||||
/**
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Range
|
||||
*/
|
||||
class Range
|
||||
{
|
||||
protected int $start;
|
||||
protected int $end;
|
||||
|
||||
public function __construct(?int $start, ?int $end, int $size)
|
||||
{
|
||||
if ($start === null && $end !== null)
|
||||
{
|
||||
// Returning requested suffix of the file
|
||||
$this->start = $size - $end;
|
||||
$this->end = $size - 1;
|
||||
}
|
||||
elseif ($start !== null && $end === null)
|
||||
{
|
||||
// Returning all bytes with offset
|
||||
$this->start = $start;
|
||||
$this->end = $size - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->start = (int)$start;
|
||||
$this->end = (int)$end;
|
||||
}
|
||||
|
||||
if ($this->start > $this->end || $this->start >= $size)
|
||||
{
|
||||
throw new ArgumentException('Requested Range Not Satisfiable');
|
||||
}
|
||||
|
||||
if ($this->end >= $size)
|
||||
{
|
||||
$this->end = $size - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public function getStart(): int
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function getEnd(): int
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $header
|
||||
* @param int $size
|
||||
* @return Range[] | null
|
||||
*/
|
||||
public static function createFromString(string $header, int $size): ?array
|
||||
{
|
||||
if (str_contains($header, '='))
|
||||
{
|
||||
[$unit, $value] = explode("=", $header);
|
||||
if (strtolower(trim($unit)) === 'bytes')
|
||||
{
|
||||
$ranges = [];
|
||||
foreach (explode(',', $value) as $range)
|
||||
{
|
||||
if (str_contains($range, '-'))
|
||||
{
|
||||
[$start, $end] = explode('-', $range);
|
||||
|
||||
if (!is_numeric($start))
|
||||
{
|
||||
$start = null;
|
||||
}
|
||||
if (!is_numeric($end))
|
||||
{
|
||||
$end = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$ranges[] = new Range($start, $end, $size);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// all ranges must be correct
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ranges ?: null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ class HttpClient implements Log\LoggerAwareInterface, ClientInterface, Http\Debu
|
||||
protected $useCurl = false;
|
||||
protected $curlLogFile = null;
|
||||
protected $shouldFetchBody = null;
|
||||
protected $sendEvents = true;
|
||||
protected Http\ResponseBuilderInterface $responseBuilder;
|
||||
|
||||
protected HttpHeaders $headers;
|
||||
@@ -93,6 +94,7 @@ class HttpClient implements Log\LoggerAwareInterface, ClientInterface, Http\Debu
|
||||
* "headers" array of headers for HTTP request.
|
||||
* "useCurl" bool Enable CURL (default false).
|
||||
* "curlLogFile" string Full path to CURL log file.
|
||||
* "sendEvents" bool Send events (default true).
|
||||
* "responseBuilder" Http\ResponseBuilderInterface Response builder.
|
||||
* Almost all options can be set separately with setters.
|
||||
*/
|
||||
@@ -177,6 +179,10 @@ class HttpClient implements Log\LoggerAwareInterface, ClientInterface, Http\Debu
|
||||
{
|
||||
$this->curlLogFile = $options['curlLogFile'];
|
||||
}
|
||||
if (isset($options['sendEvents']))
|
||||
{
|
||||
$this->sendEvents = (bool)$options['sendEvents'];
|
||||
}
|
||||
if (isset($options['responseBuilder']))
|
||||
{
|
||||
$this->setResponseBuilder($options['responseBuilder']);
|
||||
@@ -880,13 +886,16 @@ class HttpClient implements Log\LoggerAwareInterface, ClientInterface, Http\Debu
|
||||
}
|
||||
}
|
||||
|
||||
// Here's the chance to tune up the client and to rebuild the request.
|
||||
$event = new Http\RequestEvent($this, $request, 'OnHttpClientBuildRequest');
|
||||
$event->send();
|
||||
|
||||
foreach ($event->getResults() as $eventResult)
|
||||
if ($this->sendEvents)
|
||||
{
|
||||
$request = $eventResult->getRequest();
|
||||
// Here's the chance to tune up the client and to rebuild the request.
|
||||
$event = new Http\RequestEvent($this, $request, 'OnHttpClientBuildRequest');
|
||||
$event->send();
|
||||
|
||||
foreach ($event->getResults() as $eventResult)
|
||||
{
|
||||
$request = $eventResult->getRequest();
|
||||
}
|
||||
}
|
||||
|
||||
return new Http\Request(
|
||||
|
||||
@@ -63,13 +63,16 @@ class Json
|
||||
|
||||
public static function validate(string $data): bool
|
||||
{
|
||||
if (function_exists('json_validate'))
|
||||
{
|
||||
return json_validate($data);
|
||||
}
|
||||
// On PHP 8.3 replace to
|
||||
// return json_validate($data);
|
||||
|
||||
try
|
||||
{
|
||||
if ($data === 'null') // consistency with json_validate
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return json_decode(json: $data, associative: true, flags: JSON_THROW_ON_ERROR) !== null;
|
||||
}
|
||||
catch (JsonException)
|
||||
|
||||
@@ -73,12 +73,27 @@ class Uri implements \JsonSerializable, UriInterface
|
||||
}
|
||||
|
||||
$authority = $this->getAuthority();
|
||||
$path = $this->getPath();
|
||||
if ($authority != '')
|
||||
{
|
||||
$uri .= '//' . $authority;
|
||||
|
||||
if (!str_starts_with($path, '/'))
|
||||
{
|
||||
$uri .= '/';
|
||||
}
|
||||
$uri .= $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
$uri .= $path;
|
||||
}
|
||||
|
||||
$uri .= $this->getPathQuery();
|
||||
$query = $this->getQuery();
|
||||
if ($query != '')
|
||||
{
|
||||
$uri .= '?' . $query;
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
@@ -168,7 +183,7 @@ class Uri implements \JsonSerializable, UriInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path with the query.
|
||||
* Returns the path with the query. Empty path is treated as a root (/)
|
||||
* @return string
|
||||
*/
|
||||
public function getPathQuery()
|
||||
|
||||
123
core/bitrix/modules/main/lib/web/useragent/platform.php
Normal file
123
core/bitrix/modules/main/lib/web/useragent/platform.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Bitrix\Main\Web\UserAgent;
|
||||
|
||||
enum Platform: string
|
||||
{
|
||||
case Android = 'Android';
|
||||
case Ios = 'iOS';
|
||||
case Windows = 'Windows';
|
||||
case Macos = 'macOS';
|
||||
case LinuxRpm = 'Linux RPM';
|
||||
case LinuxDeb = 'Linux DEB';
|
||||
case Unknown = 'Unknown';
|
||||
|
||||
public function isMobile(): bool
|
||||
{
|
||||
return in_array($this, [self::Android, self::Ios], true);
|
||||
}
|
||||
|
||||
public function isDesktop(): bool
|
||||
{
|
||||
return in_array($this, [self::Windows, self::Macos, self::LinuxRpm, self::LinuxDeb], true);
|
||||
}
|
||||
|
||||
public function isLinux(): bool
|
||||
{
|
||||
return in_array($this, [self::LinuxRpm, self::LinuxDeb], true);
|
||||
}
|
||||
|
||||
public static function fromUserAgent(string $userAgent): self
|
||||
{
|
||||
$userAgent = strtolower($userAgent);
|
||||
|
||||
if (str_contains($userAgent, 'bitrixmobile') || str_contains($userAgent, 'bitrix24/'))
|
||||
{
|
||||
if (
|
||||
str_contains($userAgent, 'iphone')
|
||||
|| str_contains($userAgent, 'ipad')
|
||||
|| str_contains($userAgent, 'darwin')
|
||||
)
|
||||
{
|
||||
return self::Ios;
|
||||
}
|
||||
|
||||
return self::Android;
|
||||
}
|
||||
|
||||
if (self::isWindowsByUserAgent($userAgent))
|
||||
{
|
||||
return self::Windows;
|
||||
}
|
||||
|
||||
if (self::isMacosByUserAgent($userAgent))
|
||||
{
|
||||
return self::Macos;
|
||||
}
|
||||
|
||||
if (self::isLinuxByUserAgent($userAgent))
|
||||
{
|
||||
return self::getLinuxPlatform($userAgent);
|
||||
}
|
||||
|
||||
if (self::isIosByUserAgent($userAgent))
|
||||
{
|
||||
return self::Ios;
|
||||
}
|
||||
|
||||
if (self::isAndroidByUserAgent($userAgent) || str_contains($userAgent, 'carddavbitrix24'))
|
||||
{
|
||||
return self::Android;
|
||||
}
|
||||
|
||||
return self::Unknown;
|
||||
}
|
||||
|
||||
private static function isWindowsByUserAgent(string $userAgent): bool
|
||||
{
|
||||
return str_contains($userAgent, 'windows')
|
||||
|| str_contains($userAgent, 'win32')
|
||||
|| str_contains($userAgent, 'win64');
|
||||
}
|
||||
|
||||
private static function isLinuxByUserAgent(string $userAgent): bool
|
||||
{
|
||||
return str_contains($userAgent, 'linux') && !self::isAndroidByUserAgent($userAgent);
|
||||
}
|
||||
|
||||
private static function isIosByUserAgent(string $userAgent): bool
|
||||
{
|
||||
return str_contains($userAgent, 'iphone')
|
||||
|| str_contains($userAgent, 'ipad')
|
||||
|| str_contains($userAgent, 'ipod')
|
||||
|| (str_contains($userAgent, 'ios') && !str_contains($userAgent, 'windows'));
|
||||
}
|
||||
|
||||
private static function isMacosByUserAgent(string $userAgent): bool
|
||||
{
|
||||
return (str_contains($userAgent, 'mac os') && !str_contains($userAgent, 'like mac os x'))
|
||||
|| str_contains($userAgent, 'macintosh');
|
||||
}
|
||||
|
||||
private static function isAndroidByUserAgent(string $userAgent): bool
|
||||
{
|
||||
return str_contains($userAgent, 'android');
|
||||
}
|
||||
|
||||
private static function getLinuxPlatform(string $userAgent): self
|
||||
{
|
||||
if (
|
||||
str_contains($userAgent, 'rpm')
|
||||
|| str_contains($userAgent, 'fedora')
|
||||
|| str_contains($userAgent, 'centos')
|
||||
|| str_contains($userAgent, 'rhel')
|
||||
)
|
||||
{
|
||||
return self::LinuxRpm;
|
||||
}
|
||||
|
||||
return self::LinuxDeb;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user