HEX
Server: Apache
System: Linux 185.122.168.184.host.secureserver.net 5.14.0-570.52.1.el9_6.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Oct 15 06:39:08 EDT 2025 x86_64
User: barbeatleanalyti (1024)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: /home/barbeatleanalyti/www/public_html/webmail/system/Managers/Eav/Storages/Db/CommandCreator.php
<?php
/*
 * This code is licensed under AGPLv3 license or Afterlogic Software License
 * if commercial version of the product was purchased.
 * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
 */

namespace Aurora\System\Managers\Eav\Storages\Db;

/**
 * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
 * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
 * @copyright Copyright (c) 2018, Afterlogic Corp.
 *
 * @internal
 * 
 * @package EAV
 * @subpackage Storages
 */
class CommandCreator extends \Aurora\System\Db\AbstractCommandCreator
{
	/**
	 * @return string
	 */
	public function isEntityExists($mIdOrUUID)
	{
		$sWhere = is_int($mIdOrUUID) ? 
				sprintf('id = %d', $mIdOrUUID) : 
					sprintf('uuid = %s', $this->escapeString($mIdOrUUID));

		return sprintf(
			'SELECT COUNT(id) as entities_count '
			. 'FROM %seav_entities WHERE %s', 
			$this->prefix(), $sWhere
		);
	}

	/**
	 * @return string
	 */
	public function createEntity($sModule, $sType, $sUUID = '', $sParentUUID = '')
	{
		return sprintf(
			'INSERT INTO %seav_entities ( %s, %s, %s, %s ) '
			. 'VALUES ( %s, %s, %s, %s )', 
			$this->prefix(),
			$this->escapeColumn('uuid'), 
			$this->escapeColumn('module_name'), 
			$this->escapeColumn('entity_type'), 
			$this->escapeColumn('parent_uuid'), 
			empty($sUUID) ? 'UUID()' : $this->escapeString($sUUID), 
			$this->escapeString($sModule),
			$this->escapeString($sType),
			$this->escapeString($sParentUUID)
		);
	}
	
	/**
	 * @param $mIdOrUUID
	 *
	 * @return string
	 */
	public function deleteEntity($mIdOrUUID)
	{
		$sWhere = is_int($mIdOrUUID) ? 
				sprintf('id = %d', $mIdOrUUID) : 
					sprintf('uuid = %s', $this->escapeString($mIdOrUUID));

		return sprintf(
			'DELETE FROM %seav_entities WHERE %s', 
			$this->prefix(), $sWhere);
	}	
	
	/**
	 * @param $aIdsOrUUIDs
	 *
	 * @return string
	 */
	public function deleteEntities($aIdsOrUUIDs)
	{
		$sResult = '';
		if (count($aIdsOrUUIDs) > 0)
		{
			$sIdOrUUID = 'id';
			if(!is_int($aIdsOrUUIDs[0]))
			{
				$sIdOrUUID = 'uuid';
				$aIdsOrUUIDs = array_map(
					function ($mValue) {
						return $this->escapeString($mValue);
					}, 
					$aIdsOrUUIDs
				);
			}
			$sResult = sprintf(
				'DELETE FROM %seav_entities WHERE %s IN (' . implode(',', $aIdsOrUUIDs) . ')', 
				$this->prefix(), $sIdOrUUID
			);
		}
		
		return $sResult;
	}	
	
	/**
	 * 
	 * @param int|string $mIdOrUUID
	 * @return string
	 */
	public function getEntity($mIdOrUUID)
	{
		$sWhere = is_int($mIdOrUUID) ? 
				sprintf('entities.id = %d', $mIdOrUUID) : 
					sprintf('entities.uuid = %s', $this->escapeString($mIdOrUUID));
		
		$sSubSql = "
(SELECT 	   
	entities.id as entity_id, 
	entities.uuid as entity_uuid, 
	entities.parent_uuid as parent_uuid, 
	entities.entity_type, 
	entities.module_name as entity_module,
	attrs.name as attr_name,
    attrs.value as attr_value,
	%s as attr_type
FROM %seav_entities as entities
	  LEFT JOIN %seav_attributes_%s as attrs ON entities.id = attrs.id_entity
WHERE %s)
";
		
		foreach (\Aurora\System\EAV\Entity::getTypes() as $sSqlType)
		{
			$aSql[] = sprintf($sSubSql, $this->escapeString($sSqlType), $this->prefix(), $this->prefix(), $sSqlType, $sWhere);
		}
		$sSql = implode("UNION ALL
", $aSql);

		return $sSql;
	}

	/**
	 * @return string
	 */
	public function getTypes()
	{
		return sprintf('
SELECT DISTINCT entity_type FROM %seav_entities', 
			$this->prefix()
		);
	}
			
	public function prepareWhere($aWhere, $oEntity, &$aWhereAttributes, $sOperator = 'AND')
	{
		$aResultOperations = array();
		foreach ($aWhere as $sKey => $mValue)
		{
			if (strpos($sKey, '$') !== false)
			{
				list(,$sKey) = explode('$', $sKey);
				$aResultOperations[] = $this->prepareWhere($mValue, $oEntity, $aWhereAttributes, $sKey);
			}
			else
			{
				$mResultValue = null;
				$mResultOperator = '=';
				if (is_array($mValue))
				{
					if (0 < count($mValue))
					{
						$mResultValue = $mValue[0];
						$mResultOperator = $mValue[1];
					}
				}
				else
				{
					$mResultValue = $mValue;
				}
				if (isset($mResultValue))
				{
					if (strpos($sKey, '@') !== false)
					{
						list(,$sKey) = explode('@', $sKey);
					}
					
					if (!in_array($sKey, $aWhereAttributes))
					{
						$aWhereAttributes[] = $sKey;
					}
					if ($oEntity->isEncryptedAttribute($sKey))
					{
						$mResultValue = \Aurora\System\Utils::EncryptValue($mResultValue);
					}
					$bIsInOperator = false;
					if (strtolower($mResultOperator) === 'in' || strtolower($mResultOperator) === 'not in'  
						&& is_array($mResultValue))
					{
						$bIsInOperator = true;
						$mResultValue = array_map(
							function ($mValue) use ($oEntity, $sKey) {
								return $oEntity->isStringAttribute($sKey) ? $this->escapeString($mValue) : $mValue;
							}, 
							$mResultValue
						);
						$mResultValue = '(' . implode(', ', $mResultValue)  . ')';
						$sValueFormat = "%s";
					}
					else if (strtolower($mResultOperator) === 'is' || strtolower($mResultOperator) === 'is not'  )
					{
						$bIsInOperator = true;
						$sValueFormat = "%s";
					}
					else
					{
						$sValueFormat = $oEntity->isStringAttribute($sKey) ? "%s" : "%d";
					}
					if ($sKey === 'UUID')
					{
						$sResultOperation = sprintf(
							"entities.uuid %s " . $sValueFormat, 
							$mResultOperator, 
							($oEntity->isStringAttribute($sKey) && !$bIsInOperator) ? $this->escapeString($mResultValue) : $mResultValue
						);
					}
					else if ($sKey === 'EntityId')
					{
						$sResultOperation = sprintf(
							"entities.id %s " . $sValueFormat, 
							$mResultOperator, 
							($oEntity->isStringAttribute($sKey) && !$bIsInOperator) ? $this->escapeString($mResultValue) : $mResultValue
						);
					}
					else
					{
						$sResultOperation = sprintf(
							"`tbl_%s`.`value` %s " . $sValueFormat, 
							$sKey, 
							$mResultOperator, 
							($oEntity->isStringAttribute($sKey) && !$bIsInOperator) ? $this->escapeString($mResultValue) : $mResultValue
						);
					}
/*
					if ($oEntity->isDefaultValue($sKey, $mResultValue))
					{
						$sResultOperation .= sprintf(
						" OR `attr_%s` IS NULL", 
						$sKey, 
						$mResultOperator);
					}
 * 
 */
					$aResultOperations[] = $sResultOperation;
				}
			}
		}
		return sprintf(
			count($aResultOperations) > 1 ? '(%s)' : '%s', 
			implode(' ' . $sOperator . ' ', $aResultOperations)
		);
	}
	
	public function getSelectSubquery($sAttributeName, $sAttributeType)
	{
		return sprintf("
	(SELECT attributes.`value` as `attr_%s`
	FROM %seav_attributes_%s as attributes
		WHERE attributes.id_entity = entities.id AND attributes.`name` = %s) as `attr_%s`", 
		$sAttributeName,
		$this->prefix(),
		$sAttributeType,
		$this->escapeString($sAttributeName),
		$sAttributeName
		);
	}
	
	public function getJoinSubquery($sAttributeName, $sAttributeType)
	{
		return sprintf('
	LEFT JOIN %seav_attributes_%s as `tbl_%s` ON `tbl_%s`.id_entity = entities.id AND `tbl_%s`.`name` = %s',
		$this->prefix(),
		$sAttributeType,
		$sAttributeName,
		$sAttributeName,
		$sAttributeName,
		$this->escapeString($sAttributeName)
		);
	}
	
	public function getIdsOrUUIDsWhere($aIdsOrUUIDs)
	{
		$sIdsOrUUIDsWhere = '';
		if (0 < count($aIdsOrUUIDs))
		{
			$aIds = array();
			$aUUIDs = array();
			foreach ($aIdsOrUUIDs as $mIdOrUUID)
			{
				if (!is_numeric($mIdOrUUID))
				{
					$aUUIDs[] = $this->escapeString($mIdOrUUID);
				}
				else
				{
					$aIds[] = $mIdOrUUID;
				}
			}

			$bHasUUIDs = false;
			if (count($aUUIDs) > 0)
			{
				$bHasUUIDs = true;
				$sIdsOrUUIDsWhere .= sprintf(
					' AND entities.uuid IN (%s)', 
					implode(',', $aUUIDs)
				);
			}
			if (count($aIds) > 0)
			{
				$sIdsOrUUIDsWhere .= sprintf(
					' %s entities.id IN (%s)', 
					$bHasUUIDs ? 'OR' : 'AND',
					implode(',', $aIds)
				);
			}
		}
		return $sIdsOrUUIDsWhere;
	}
	
	public function getEntitiesByUUID($sEntityType, $iOffset = 0, $iLimit = 0, $aWhere = array(), $mOrderAttributes = array(), 
			$iSortOrder = \Aurora\System\Enums\SortOrder::ASC)
	{
		$this->oCommandCreator->getEntities(
			$sEntityType, 
			array('UUID'), 
			$iOffset, 
			$iLimit, 
			$aWhere,
			$mOrderAttributes,
			$iSortOrder
		);
	}
			
	/**
	 * 
	 * @param type $sType
	 * @param type $aWhere
	 * @param type $aIdsOrUUIDs
	 * @return type
	 */
	public function getEntitiesCount($sType, $aWhere = array(), $aIdsOrUUIDs = array())
	{
		return $this->getEntities(
			$sType, 
			array('UUID'), 
			0, 
			0, 
			$aWhere, 
			null, 
			\Aurora\System\Enums\SortOrder::ASC, 
			$aIdsOrUUIDs, 
			true
		);
	}

	/**
	 * 
	 * @param type $sEntityType
	 * @param type $aViewAttributes
	 * @param type $iOffset
	 * @param type $iLimit
	 * @param type $aWhere
	 * @param string|array $mOrderAttributes
	 * @param type $iSortOrder
	 * @param type $aIdsOrUUIDs
	 * @param type $bCount
	 * @return type
	 * 
		$aWhere = [
		   '$OR' => [
			   '$AND' => [
				   'IdUser' => [
					   1,
					   '='
				   ],
				   'Storage' => [
					   'personal',
					   '='
				   ]
			   ],
			   'Storage' => [
				   'global',
				   '='
			   ]
		   ]
	   ];
	 */	
	public function getEntities($sEntityType, $aViewAttributes = array(), 
			$iOffset = 0, $iLimit = 0, $aWhere = array(), $mOrderAttributes = array(), 
			$iSortOrder = \Aurora\System\Enums\SortOrder::ASC, $aIdsOrUUIDs = array(), $bCount = false)
	{
		$sViewAttributes = "";
		$sWhereAttributes = "";
		$sResultWhere = "";
		$sResultSort = "";
		$sLimit = "";
		$sOffset = "";
		
		$oEntity = \Aurora\System\EAV\Entity::createInstance($sEntityType);
		
		if ($oEntity instanceof $sEntityType)
		{
			$aResultViewAttributes = array(
				'EntityId' => 'entities.id as attr_EntityId', 
				'UUID' => 'entities.uuid as attr_UUID', 
				'ParentUUID' => 'entities.parent_uuid as attr_ParentUUID', 
				'EntityType' => 'entities.entity_type as attr_EntityType', 
				'ModuleName' => 'entities.module_name as attr_ModuleName'				
			);
			$aResultWhereAttributes = array();
			
			if ($aViewAttributes === null)
			{
				$aViewAttributes = array();
			}
			if (!is_array($mOrderAttributes) && !empty($mOrderAttributes))
			{
				$mOrderAttributes = array($mOrderAttributes);
			}
			
			$aWhereAttributes = array();
			if (is_array($mOrderAttributes) && count($mOrderAttributes) > 0)
			{
				$aWhereAttributes = array_merge(
					$aWhereAttributes, 
					$mOrderAttributes
				);
				$mOrderWhere = array_map(function ($sValue) {
					return sprintf("`tbl_%s`.`value`", $sValue) . ' IS NOT NULL';
				}, $mOrderAttributes);
				$mOrderAttributes = array_map(function($sValue){
					return sprintf("`attr_%s`", $sValue);
				}, $mOrderAttributes);

				
				$mOrderAttributes = array_map(function ($sSortField) use ($iSortOrder) {
					return $sSortField . ' ' . ($iSortOrder === \Aurora\System\Enums\SortOrder::ASC ? "ASC" : "DESC");
				}, $mOrderAttributes);

				if (count($mOrderAttributes) > 0)
				{
					$sResultSort = 'ORDER BY ' . implode(', ', $mOrderAttributes);
					$sResultWhere .= ' AND ' . implode(' AND ', $mOrderWhere);
				}
				else
				{
					$sResultSort = 'ORDER BY ' . implode(', ', $mOrderAttributes);
				}
			}
			else
			{
				$sResultSort = 'ORDER BY attr_EntityId';
			}
			
			if (0 < count($aWhere))
			{
				$sResultWhere .= ' AND ' . $this->prepareWhere($aWhere, $oEntity, $aWhereAttributes);
			}

			foreach ($aViewAttributes as $sAttribute)
			{
				if (!$oEntity->isSystemAttribute($sAttribute))
				{
					$aResultViewAttributes[$sAttribute] = $this->getSelectSubquery(
						$sAttribute, 
						$oEntity->getType($sAttribute)
					);
				}
			}
			foreach ($aWhereAttributes as $sAttribute)
			{
				if (!$oEntity->isSystemAttribute($sAttribute))
				{
					$aResultWhereAttributes[$sAttribute] = $this->getJoinSubquery(
						$sAttribute, 
						$oEntity->getType($sAttribute)
					);
					$aResultViewAttributes[$sAttribute] = sprintf('
	`tbl_%s`.`value` as `attr_%s`', $sAttribute, $sAttribute);
				}
			}
			if (0 < count($aResultWhereAttributes))
			{
				$sWhereAttributes = implode(' ', $aResultWhereAttributes);
			}
			if (0 < count($aResultViewAttributes))
			{
				$sViewAttributes = implode(', ', $aResultViewAttributes);
			}

			if ($iLimit > 0)
			{
				$sLimit = sprintf("LIMIT %d", $iLimit);
				$sOffset = sprintf("OFFSET %d", $iOffset);
			}
		}	
		
		$sSql = sprintf("
	SELECT 
		# fields
		%s #1
		# ------
	FROM %seav_entities as entities #2
		#3 fields
		%s
		# ------
	WHERE entities.entity_type = %s  #4 ENTITY TYPE
		%s #5
		%s #6 WHERE
", 
			$bCount ? 'count(*) as entities_count' : $sViewAttributes, 
			$this->prefix(),
			$sWhereAttributes, 
			$this->escapeString($sEntityType), 
			$this->getIdsOrUUIDsWhere($aIdsOrUUIDs),
			$sResultWhere
		);
		
		if (!$bCount)
		{
			$sSql = sprintf("
SELECT * FROM 
	(%s) AS S1
	%s #7 SORT
	%s /*8 LIMIT*/ %s /*9 OFFSET*/
", 
			$sSql,
			$sResultSort,
			$sLimit,
			$sOffset
			);
		}
		
		\Aurora\System\Api::Log($sSql, \Aurora\System\Enums\LogLevel::Full, "sql-");
		
		return $sSql;
	}	
	
	/**
	 * @param array $aEntities
	 * @param array $aAttributes
	 *
	 * @return string
	 */
	public function setAttributes($aEntities, $aAttributes, $sType)
	{
		$sSql = '';
		$aSql = array();
		$aSqlDelete = array();
		$aValues = array();
		foreach ($aEntities as $oEntity)
		{
			$iEntityId = $oEntity->EntityId;
			foreach ($aAttributes as $oAttribute)
			{
				if ($oAttribute instanceof \Aurora\System\EAV\Attribute && !$oEntity->isSystemAttribute($oAttribute->Name))
				{
					if ((!$oEntity->isDefaultValue($oAttribute->Name, $oAttribute->Value) || ($oEntity->isOverridedAttribute($oAttribute->Name))) && (!$oAttribute->Inherited))
					{
						if ($oAttribute->IsEncrypt && !$oAttribute->Encrypted)
						{
							$oAttribute->Encrypt();
						}
						$mValue = $oAttribute->Value;
						$mValue = is_null($mValue) ? 'null' : $mValue;
						$sSqlValue = $oAttribute->needToEscape() ? $this->escapeString($mValue) : $mValue;
						$sSqlValueType = $oAttribute->getValueFormat();

						$aValues[] = sprintf('	(%d, %s, ' . $sSqlValueType . ')',
							$iEntityId,
							$this->escapeString($oAttribute->Name),
							$sSqlValue
						);
					}
					else
					{
						$aSqlDelete[] = sprintf(
							'id_entity = %d AND name = %s',
							$iEntityId,
							$this->escapeString($oAttribute->Name)
						);
					}
				}
			}
		}
		if (count($aValues) > 0)
		{
			$sValues = implode(",\r\n", $aValues);

			$aSql[] = $sSql . sprintf('
INSERT INTO %seav_attributes_%s 
	(%s, %s, %s)
VALUES 
%s
ON DUPLICATE KEY UPDATE 
	%s=VALUES(%s),
	%s=VALUES(%s),
	%s=VALUES(%s);
', 
				$this->prefix(), 
				$sType, 
				$this->escapeColumn('id_entity'), 
				$this->escapeColumn('name'),
				$this->escapeColumn('value'),
				$sValues,
				$this->escapeColumn('id_entity'), $this->escapeColumn('id_entity'), 
				$this->escapeColumn('name'), $this->escapeColumn('name'),
				$this->escapeColumn('value'), $this->escapeColumn('value')
			);
		}
		if (count($aSqlDelete) > 0)
		{
			array_unshift($aSql, sprintf(
				'DELETE FROM %seav_attributes_%s WHERE ' . implode(" OR ", $aSqlDelete) . ";",
				$this->prefix(), 
				$sType
			));
		}
		return $aSql;
	}	
	
	public function deleteAttribute($sType, $iEntityId, $sAttribute)
	{
		return sprintf(
			'DELETE FROM %seav_attributes_%s WHERE id_entity = %d AND name = %s', 
			$this->prefix(), $sType, $iEntityId, $this->escapeString($sAttribute));		
	}
	
	public function getAttributesNamesByEntityType($sEntityType)
	{
		$sSubSql = "
(SELECT DISTINCT name FROM %seav_attributes_%s as attrs, %seav_entities as entities
	WHERE entity_type = %s AND entities.id = attrs.id_entity)
";
		
		foreach (\Aurora\System\EAV\Entity::getTypes() as $sSqlType)
		{
			$aSql[] = sprintf($sSubSql, $this->prefix(), $sSqlType, $this->prefix(), $this->escapeString($sEntityType));
		}
		$sSql = implode("UNION ALL
", $aSql);

		return $sSql;
	}
}