Your IP : 18.225.254.30


Current Path : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/tasks/lib/task/
Upload File :
Current File : /home/bitrix/ext_www/crm.klimatlend.ua/bitrix/modules/tasks/lib/task/dependence.php

<?php
namespace Bitrix\Tasks\Task;

use \Bitrix\Main\Entity;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Type\DateTime;
use \Bitrix\Main\NotImplementedException;
use \Bitrix\Main\Entity\AddResult;
use \Bitrix\Main\Error;
use \Bitrix\Main\HttpApplication;

use \Bitrix\Tasks\TaskTable;
use \Bitrix\Tasks\DB\Mesh;
use \Bitrix\Tasks\DB\Tree;
use \Bitrix\Tasks\Util\Assert;
use \Bitrix\Tasks\ActionFailedException;

Loc::loadMessages(__FILE__);

/**
 * Class DependenceTable
 * 
 * Fields:
 * <ul>
 * <li> TASK_ID int mandatory
 * <li> DEPENDS_ON_ID int mandatory
 * </ul>
 *
 * @package Bitrix\Tasks
 * 
 * See GanttDependency (tasks/install/public/js/tasks/gantt.js) for client-side implementation of this logic
 * This class does not check rights
 * 
 **/

final class DependenceTable extends Mesh
{
	const LINK_TYPE_START_START = 		0x00;
	const LINK_TYPE_START_FINISH = 		0x01;
	const LINK_TYPE_FINISH_START = 		0x02;
	const LINK_TYPE_FINISH_FINISH = 	0x03;

	/**
	 * Returns DB table name for entity.
	 *
	 * @return string
	 */
	public static function getTableName()
	{
		return 'b_tasks_proj_dep';
	}

	public static function getIDColumnName()
	{
		return 'TASK_ID';
	}

	public static function getPARENTIDColumnName()
	{
		return 'DEPENDS_ON_ID';
	}

	protected static function allowMultipleParents()
	{
		return true;
	}

	public static function getLinkCountForUser($userId = 0)
	{
		if(!$userId)
		{
			$userId = \Bitrix\Tasks\Util\User::getId();
		}

		$item = \Bitrix\Main\HttpApplication::getConnection()->query("select count(*) as CNT from ".static::getTableName()." where ".static::getDIRECTColumnName()." = '1' and CREATOR_ID = '".intval($userId)."'")->fetch();

		return intval($item['CNT']);
	}

	public static function createLink($id, $parentId, $behaviour = array())
	{
		// bless the php7
		// was: ($id, $parentId, $type = self::LINK_TYPE_FINISH_START, array $behaviour = array())

		$type = self::LINK_TYPE_FINISH_START;

		if(func_num_args() > 2) // the third argument may be $type or $behaviour
		{
			$arg3 = func_get_arg(2);
			if(is_array($arg3))
			{
				$behaviour = $arg3;
			}
			else
			{
				$type = $arg3;
				if(func_num_args() > 3)
				{
					$behaviour = func_get_arg(3);
				}
			}
		}
		else
		{
			$behaviour = array();
		}

		if(array_key_exists('LINK_TYPE', $behaviour))
		{
			$type = $behaviour['LINK_TYPE'];
		}

		$id = 			Assert::expectIntegerPositive($id, '$id');
		$parentId = 	Assert::expectIntegerPositive($parentId, '$parentId');
		$type = 		Assert::expectEnumerationMember($type, array(
			self::LINK_TYPE_START_START,
			self::LINK_TYPE_START_FINISH,
			self::LINK_TYPE_FINISH_START,
			self::LINK_TYPE_FINISH_FINISH
		), '$type');

		$exceptionInfo = array(
			'AUX' => array(
				'MESSAGE' => array(
					'FROM_TASK_ID' => $parentId,
					'TASK_ID' => $id,
					'LINK_TYPE' => $type
				)
			)
		);

		$result = new AddResult();

		if(is_array($behaviour['TASK_DATA']) && !empty($behaviour['TASK_DATA']))
		{
			$toTask = $behaviour['TASK_DATA'];
		}
		else
		{
			$toTask = 	TaskTable::getById($id)->fetch();
		}
		if(empty($toTask))
		{
			throw new ActionFailedException('Task not found', $exceptionInfo);
		}

		if(is_array($behaviour['PARENT_TASK_DATA']) && !empty($behaviour['PARENT_TASK_DATA']))
		{
			$fromTask = $behaviour['PARENT_TASK_DATA'];
		}
		else
		{
			$fromTask = 	TaskTable::getById($parentId)->fetch();
		}
		if(empty($fromTask))
		{
			throw new ActionFailedException('Parent task not found', $exceptionInfo);
		}

		if((string) $toTask['CREATED_DATE'] == '')
		{
			$result->addError(new Error(Loc::getMessage('DEPENDENCE_ENTITY_CANT_ADD_LINK_CREATED_DATE_NOT_SET')));
		}
		if((string) $toTask['END_DATE_PLAN'] == '')
		{
			$result->addError(new Error(Loc::getMessage('DEPENDENCE_ENTITY_CANT_ADD_LINK_END_DATE_PLAN_NOT_SET')));
		}

		if((string) $fromTask['CREATED_DATE'] == '')
		{
			$result->addError(new Error(Loc::getMessage('DEPENDENCE_ENTITY_CANT_ADD_LINK_CREATED_DATE_NOT_SET_PARENT_TASK')));
		}
		if((string) $fromTask['END_DATE_PLAN'] == '')
		{
			$result->addError(new Error(Loc::getMessage('DEPENDENCE_ENTITY_CANT_ADD_LINK_END_DATE_PLAN_NOT_SET_PARENT_TASK')));
		}

		if(!$result->isSuccess())
		{
			return $result;
		}
		else
		{
			$linkData = array('TYPE' => $type);
			if(array_key_exists('CREATOR_ID', $behaviour) && intval($behaviour['CREATOR_ID']))
			{
				$linkData['CREATOR_ID'] = $behaviour['CREATOR_ID'];
			}

			return parent::createLink($id, $parentId, array('LINK_DATA' => $linkData));
		}
	}

	protected static function applyCreateRestrictions(&$id, &$parentId)
	{
		if(static::checkLinkExists($id, $parentId, array('BIDIRECTIONAL' => true)))
		{
			throw new Tree\LinkExistsException(false, array('NODES' => array($id, $parentId)));
		}
	}

	public static function checkLinkExists($id, $parentId, array $parameters = array('BIDIRECTIONAL' => false))
	{
		$parentColName = static::getPARENTIDColumnName();
		$idColName = static::getIDColumnName();
		//$directColName = static::getDIRECTColumnName();

		$id = intval($id);
		$parentId = intval($parentId);
		if(!$id || !$parentId)
		{
			return false; // link to non-existed nodes does not exist
		}

		$item = HttpApplication::getConnection()->query("
			select ".$idColName." 
				from 
					".static::getTableName()." 
				where 
					(
						".$idColName." = '".$id."' 
						and ".$parentColName." = '".$parentId."' 
					)
					".($parameters['BIDIRECTIONAL'] ? "

					or
					(
						".$idColName." = '".$parentId."' 
						and ".$parentColName." = '".$id."' 
					)

					" : "")."
			")->fetch();

		return is_array($item);
	}

	protected static function applyDeleteRestrictions(&$id, &$parentId)
	{
		$id = 			Assert::expectIntegerPositive($id, '$id');
		//$parentId = 	Assert::expectIntegerPositive($parentId, '$parentId');

		if($parentId !== false && !static::checkLinkExists($id, $parentId))
		{
			throw new Tree\LinkNotExistException(false, array('NODES' => array($id, $parentId)));
		}
	}

	/**
	 * Returns a list of INGOING DIRECT links according to the old-style (sutable for CTask::GetList()) filter
	 * A heavy-artillery function
	 */
	public static function getListByLegacyTaskFilter(array $filter = array(), array $parameters = array())
	{
		$mixins = TaskTable::getRuntimeMixins(
			array(
				array(
					'CODE' => 			'LEGACY_FILTER',
					'FILTER' => 		$filter,
					'REF_FIELD' => 		'TASK_ID',
				)
			)
		);

		if(!empty($mixins))
		{
			if(!is_array($parameters['runtime']))
			{
				$parameters['runtime'] = array();
			}

			$parameters['runtime'] = array_merge($parameters['runtime'], $mixins);
		}

		$parameters['filter']['=DIRECT'] = '1';

		return self::getList($parameters);
	}

	/**
	 * For better perfomance purposes
	 */
	public static function getSubTreeSql($id)
	{
		$id = Assert::expectIntegerPositive($id, '$id');

		global $DB;

		$tableName = 		static::getTableName();

		$parentColName = 	static::getPARENTIDColumnName();
		$idColName = 		static::getIDColumnName();
		$directColName = 	static::getDIRECTColumnName();

		// select STATUS as REAL_STATUS, according to the CTasks::GetList() behaviour
		// (in \Bitrix\Tasks\TaskTable there is different alias naming)

		/*
		--DEP_T.DURATION_PLAN as DURATION_PLAN,
		*/

		// enough data to say if and how we can change dates
		// look also at \Bitrix\Tasks\Util\Scheduler::initializeTargetTask()

		// CDatabase::DateToCharFunction() converts database format like "2015-10-15 00:00:00"
		// to a site format: "22.06.2015 11:39:50", and optionally adds the timezone offset
		return "
			select 
				DEP.".$idColName." as ".$idColName.",
				DEP_P.TYPE as TYPE,
				DEP_P.".$parentColName." as FROM_TASK_ID,

				DEP_T.ID as ID,
				DEP_T.MATCH_WORK_TIME as MATCH_WORK_TIME,
				DEP_T.ALLOW_CHANGE_DEADLINE as ALLOW_CHANGE_DEADLINE,
				DEP_T.DURATION_TYPE as DURATION_TYPE,

				DEP_T.RESPONSIBLE_ID as RESPONSIBLE_ID,
				DEP_T.CREATED_BY as CREATED_BY,
				DEP_T.GROUP_ID as GROUP_ID,
				DEP_T.STATUS as REAL_STATUS,

				".$DB->DateToCharFunction("DEP_T.CREATED_DATE", "FULL")." as CREATED_DATE,
				".$DB->DateToCharFunction("DEP_T.START_DATE_PLAN", "FULL")." as START_DATE_PLAN,
				".$DB->DateToCharFunction("DEP_T.END_DATE_PLAN", "FULL")." as END_DATE_PLAN
			from 
				".$tableName." DEP

			inner join 
				b_tasks DEP_T
					on 
						DEP.".$idColName." = DEP_T.ID
			inner join 
				".$tableName." DEP_P 
					on 
						DEP_P.".$directColName." = '1'and DEP.".$idColName." = DEP_P.".$idColName."

			where DEP.".$parentColName." = '".intval($id)."'
		";
	}

	// unused
	/*
	protected static function getRelationHash($id, array $parameters = array())
	{
		$id = intval($id);
		$result = array();

		if($id)
		{
			$parameters['select'][] = 'TASK_ID';
			$parameters['select']['TYPE_'] = 'PARENT_NODE.TYPE';
			$parameters['select']['FROM_TASK_ID'] = 'PARENT_NODE.DEPENDS_ON_ID';

			$res = static::getSubTree($id, $parameters, array(
				'INCLUDE_SELF' => true
			));
			$res->addReplacedAliases(array('TYPE_' => 'TYPE'));

			$items = array(); // all items
			$taskIds = array($id => true); // actual task list in bundle
			while($item = $res->fetch())
			{
				$items[] = $item;
				$taskIds[$item['TASK_ID']] = true;
			}

			// due to multiple-parent relations there are extraneous links possibe (came from join)
			// throw them out

			$result = array();
			foreach($items as $item)
			{
				if(isset($taskIds[$item['FROM_TASK_ID']]))
				{
					$pid = $item['FROM_TASK_ID'];
					$result[$pid][$item['TASK_ID']] = $item;
				}
			}
		}

		return $result;
	}
	*/

	/**
	 * Returns entity map definition.
	 *
	 * @return array
	 */
	public static function getMap()
	{
		// to avoid warnings in php7
		$entityName = '\\Bitrix\\Tasks\\TaskTable';
		if(func_num_args() > 0)
		{
			$entityName = func_get_arg(0);
		}

		$map = array_merge(array(
			new Entity\IntegerField('TASK_ID', array(
				'primary' => true,
				'title' => Loc::getMessage('DEPENDENCE_ENTITY_TASK_ID_FIELD'),
				'required' => true
			)),
			new Entity\IntegerField('DEPENDS_ON_ID', array(
				'primary' => true,
				'title' => Loc::getMessage('DEPENDENCE_ENTITY_DEPENDS_ON_ID_FIELD'),
				'required' => true
			)),
			new Entity\IntegerField('TYPE', array(
				'title' => Loc::getMessage('DEPENDENCE_ENTITY_TYPE_FIELD'),
				//'validation' => array(__CLASS__, 'validateType'),
			)),
			new Entity\IntegerField('CREATOR_ID', array(
			)),
			new Entity\ReferenceField(
				'TASK',
				$entityName,
				array(
					'=this.TASK_ID' => 'ref.ID',
				)
			),
			new Entity\ReferenceField(
				'DEPENDS_ON',
				$entityName,
				array(
					'=this.DEPENDS_ON_ID' => 'ref.ID',
				)
			)
		), parent::getMap('\\Bitrix\\Tasks\\Task\\Dependence'));

		return $map;
	}

	/**
	 * Returns validators for TYPE field.
	 *
	 * @return array
	 */
	public static function validateType()
	{
		return array(
			new Entity\Validator\Enum(null, array(
				static::LINK_TYPE_START_START,
				static::LINK_TYPE_START_FINISH,
				static::LINK_TYPE_FINISH_START,
				static::LINK_TYPE_FINISH_FINISH
			)),
		);
	}

	public static function moveLink($id, $parentId, $behaviour = array('CREATE_PARENT_NODE_ON_NOTFOUND' => true))
	{
		throw new NotImplementedException('Calling moveLink() is meaningless for this entity');
	}

	public static function link($id, $parentId)
	{
		throw new NotImplementedException('Calling link() is meaningless for this entity');
	}

	public static function unlink($id)
	{
		throw new NotImplementedException('Calling unlink() is meaningless for this entity');
	}
}