Bitrix-D7  20.0.0
main/lib/orm/data/datamanager.php
См. документацию.
1 <?php
2 /**
3  * Bitrix Framework
4  * @package bitrix
5  * @subpackage main
6  * @copyright 2001-2013 Bitrix
7  */
8 
9 namespace Bitrix\Main\ORM\Data;
10 
11 use Bitrix\Main;
21 use Bitrix\Main\ORM\Query\Result as QueryResult;
26 
27 Loc::loadMessages(__FILE__);
28 
29 /**
30  * Base entity data manager
31  */
32 abstract class DataManager
33 {
34  const EVENT_ON_BEFORE_ADD = "OnBeforeAdd";
35  const EVENT_ON_ADD = "OnAdd";
36  const EVENT_ON_AFTER_ADD = "OnAfterAdd";
37  const EVENT_ON_BEFORE_UPDATE = "OnBeforeUpdate";
38  const EVENT_ON_UPDATE = "OnUpdate";
39  const EVENT_ON_AFTER_UPDATE = "OnAfterUpdate";
40  const EVENT_ON_BEFORE_DELETE = "OnBeforeDelete";
41  const EVENT_ON_DELETE = "OnDelete";
42  const EVENT_ON_AFTER_DELETE = "OnAfterDelete";
43 
44  /** @var Entity[] */
45  protected static $entity;
46 
47  /** @var EntityObject[] Cache of class names */
48  protected static $objectClass;
49 
50  /** @var Collection[] Cache of class names */
51  protected static $collectionClass;
52 
53  /** @var array Restricted words for object class name */
54  protected static $reservedWords = [
55  // keywords
56  'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue',
57  'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach',
58  'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'finally', 'for', 'foreach', 'function',
59  'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset',
60  'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return',
61  'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor', 'yield',
62  // classes
63  'self', 'parent',
64  // others
65  'int', 'float', 'bool', 'string', 'true', 'false', 'null', 'void', 'iterable', 'object', 'resource', 'mixed', 'numeric',
66  ];
67 
68  /**
69  * Returns entity object
70  *
71  * @return Entity
72  * @throws Main\ArgumentException
73  * @throws Main\SystemException
74  */
75  public static function getEntity()
76  {
77  $class = static::getEntityClass()::normalizeEntityClass(get_called_class());
78 
79  if (!isset(static::$entity[$class]))
80  {
81  static::$entity[$class] = static::getEntityClass()::getInstance($class);
82  }
83 
84  return static::$entity[$class];
85  }
86 
87  public static function unsetEntity($class)
88  {
89  $class = static::getEntityClass()::normalizeEntityClass($class);
90 
91  if (isset(static::$entity[$class]))
92  {
93  unset(static::$entity[$class]);
94  }
95  }
96 
97  /**
98  * Returns DB table name for entity
99  *
100  * @return string
101  */
102  public static function getTableName()
103  {
104  return null;
105  }
106 
107  /**
108  * Returns connection name for entity
109  *
110  * @return string
111  */
112  public static function getConnectionName()
113  {
114  return 'default';
115  }
116 
117  /**
118  * @return string
119  */
120  public static function getTitle()
121  {
122  return null;
123  }
124 
125  /**
126  * Returns class of Object for current entity.
127  *
128  * @return string|EntityObject
129  */
130  public static function getObjectClass()
131  {
132  if (!isset(static::$objectClass[get_called_class()]))
133  {
134  static::$objectClass[get_called_class()] = static::getObjectClassByDataClass(get_called_class());
135  }
136 
137  return static::$objectClass[get_called_class()];
138  }
139 
140  /**
141  * Returns class name (without namespace) of Object for current entity.
142  *
143  * @return string
144  */
145  final public static function getObjectClassName()
146  {
147  $class = static::getObjectClass();
148  return substr($class, strrpos($class, '\\')+1);
149  }
150 
151  protected static function getObjectClassByDataClass($dataClass)
152  {
153  $objectClass = static::getEntityClass()::normalizeName($dataClass);
154 
155  // make class name more unique
156  $namespace = substr($objectClass, 0, strrpos($objectClass, '\\')+1);
157  $className = substr($objectClass, strrpos($objectClass, '\\') + 1);
158 
159  $className = static::getEntityClass()::getDefaultObjectClassName($className);
160 
161  return $namespace.$className;
162  }
163 
164  /**
165  * Returns class of Object collection for current entity.
166  *
167  * @return string|Collection
168  */
169  public static function getCollectionClass()
170  {
171  if (!isset(static::$collectionClass[get_called_class()]))
172  {
173  static::$collectionClass[get_called_class()] = static::getCollectionClassByDataClass(get_called_class());
174  }
175 
176  return static::$collectionClass[get_called_class()];
177  }
178 
179  /**
180  * Returns class name (without namespace) of Object collection for current entity.
181  *
182  * @return string
183  */
184  final public static function getCollectionClassName()
185  {
186  $class = static::getCollectionClass();
187  return substr($class, strrpos($class, '\\')+1);
188  }
189 
190  protected static function getCollectionClassByDataClass($dataClass)
191  {
192  $objectClass = static::getEntityClass()::normalizeName($dataClass);
193 
194  // make class name more unique
195  $namespace = substr($objectClass, 0, strrpos($objectClass, '\\')+1);
196  $className = substr($objectClass, strrpos($objectClass, '\\') + 1);
197 
198  $className = static::getEntityClass()::getDefaultCollectionClassName($className);
199 
200  return $namespace.$className;
201  }
202 
203  /**
204  * @return EntityObject|string
205  */
206  public static function getObjectParentClass()
207  {
208  return EntityObject::class;
209  }
210 
211  /**
212  * @return Collection|string
213  */
214  public static function getCollectionParentClass()
215  {
216  return Collection::class;
217  }
218 
219  /**
220  * @return Query|string
221  */
222  public static function getQueryClass()
223  {
224  return Query::class;
225  }
226 
227  /**
228  * @return Entity|string
229  */
230  public static function getEntityClass()
231  {
232  return Entity::class;
233  }
234 
235  /**
236  * @param bool $setDefaultValues
237  *
238  * @return null Actual type should be annotated by orm:annotate
239  * @throws Main\ArgumentException
240  * @throws Main\SystemException
241  */
242  final public static function createObject($setDefaultValues = true)
243  {
244  return static::getEntity()->createObject($setDefaultValues);
245  }
246 
247  /**
248  * @return null Actual type should be annotated by orm:annotate
249  * @throws Main\ArgumentException
250  * @throws Main\SystemException
251  */
252  final public static function createCollection()
253  {
254  return static::getEntity()->createCollection();
255  }
256 
257  /**
258  * @see EntityObject::wakeUp()
259  *
260  * @param $row
261  *
262  * @return null Actual type should be annotated by orm:annotate
263  * @throws Main\ArgumentException
264  * @throws Main\SystemException
265  */
266  final public static function wakeUpObject($row)
267  {
268  return static::getEntity()->wakeUpObject($row);
269  }
270 
271  /**
272  * @see Collection::wakeUp()
273  *
274  * @param $rows
275  *
276  * @return null Actual type should be annotated by orm:annotate
277  * @throws Main\ArgumentException
278  * @throws Main\SystemException
279  */
280  final public static function wakeUpCollection($rows)
281  {
282  return static::getEntity()->wakeUpCollection($rows);
283  }
284 
285  /**
286  * Returns entity map definition.
287  * To get initialized fields @see \Bitrix\Main\ORM\Entity::getFields() and \Bitrix\Main\ORM\Entity::getField()
288  */
289  public static function getMap()
290  {
291  return array();
292  }
293 
294  public static function getUfId()
295  {
296  return null;
297  }
298 
299  public static function isUts()
300  {
301  return false;
302  }
303 
304  public static function isUtm()
305  {
306  return false;
307  }
308 
309  /**
310  * @param Query $query
311  *
312  * @return Query
313  */
314  public static function setDefaultScope($query)
315  {
316  return $query;
317  }
318 
319  /**
320  * @param Entity $entity
321  *
322  * @return null
323  */
324  public static function postInitialize(Entity $entity)
325  {
326  return null;
327  }
328 
329  /**
330  * Returns selection by entity's primary key and optional parameters for getList()
331  *
332  * @param mixed $primary Primary key of the entity
333  * @param array $parameters Additional parameters for getList()
334  *
335  * @return QueryResult
336  * @throws Main\ArgumentException
337  * @throws Main\ObjectPropertyException
338  * @throws Main\SystemException
339  */
340  public static function getByPrimary($primary, array $parameters = array())
341  {
342  static::normalizePrimary($primary);
343  static::validatePrimary($primary);
344 
345  $primaryFilter = array();
346 
347  foreach ($primary as $k => $v)
348  {
349  $primaryFilter['='.$k] = $v;
350  }
351 
352  if (isset($parameters['filter']))
353  {
354  $parameters['filter'] = array($primaryFilter, $parameters['filter']);
355  }
356  else
357  {
358  $parameters['filter'] = $primaryFilter;
359  }
360 
361  return static::getList($parameters);
362  }
363 
364  /**
365  * Returns selection by entity's primary key
366  *
367  * @param mixed $id Primary key of the entity
368  *
369  * @return QueryResult
370  * @throws Main\ArgumentException
371  * @throws Main\ObjectPropertyException
372  * @throws Main\SystemException
373  */
374  public static function getById($id)
375  {
376  return static::getByPrimary($id);
377  }
378 
379  /**
380  * Returns one row (or null) by entity's primary key
381  *
382  * @param mixed $id Primary key of the entity
383  *
384  * @return array|null
385  * @throws Main\ArgumentException
386  * @throws Main\ObjectPropertyException
387  * @throws Main\SystemException
388  */
389  public static function getRowById($id)
390  {
391  $result = static::getByPrimary($id);
392  $row = $result->fetch();
393 
394  return (is_array($row)? $row : null);
395  }
396 
397  /**
398  * Returns one row (or null) by parameters for getList()
399  *
400  * @param array $parameters Primary key of the entity
401  *
402  * @return array|null
403  * @throws Main\ArgumentException
404  * @throws Main\ObjectPropertyException
405  * @throws Main\SystemException
406  */
407  public static function getRow(array $parameters)
408  {
409  $parameters['limit'] = 1;
410  $result = static::getList($parameters);
411  $row = $result->fetch();
412 
413  return (is_array($row)? $row : null);
414  }
415 
416  /**
417  * Executes the query and returns selection by parameters of the query. This function is an alias to the Query object functions
418  *
419  * @param array $parameters An array of query parameters, available keys are:<br>
420  * "select" => array of fields in the SELECT part of the query, aliases are possible in the form of "alias"=>"field";<br>
421  * "filter" => array of filters in the WHERE/HAVING part of the query in the form of "(condition)field"=>"value";
422  * also could be an instance of Filter;<br>
423  * "group" => array of fields in the GROUP BY part of the query;<br>
424  * "order" => array of fields in the ORDER BY part of the query in the form of "field"=>"asc|desc";<br>
425  * "limit" => integer indicating maximum number of rows in the selection (like LIMIT n in MySql);<br>
426  * "offset" => integer indicating first row number in the selection (like LIMIT n, 100 in MySql);<br>
427  * "runtime" => array of entity fields created dynamically;<br>
428  * "cache => array of cache options:<br>
429  * "ttl" => integer indicating cache TTL;<br>
430  * "cache_joins" => boolean enabling to cache joins, false by default.
431  * @see Query::filter()
432  *
433  * @return QueryResult
434  * @throws Main\ArgumentException
435  * @throws Main\ObjectPropertyException
436  * @throws Main\SystemException
437  */
438  public static function getList(array $parameters = array())
439  {
440  $query = static::query();
441 
442  if(!isset($parameters['select']))
443  {
444  $query->setSelect(array('*'));
445  }
446 
447  foreach($parameters as $param => $value)
448  {
449  switch($param)
450  {
451  case 'select':
452  $query->setSelect($value);
453  break;
454  case 'filter':
455  $value instanceof Filter ? $query->where($value) : $query->setFilter($value);
456  break;
457  case 'group':
458  $query->setGroup($value);
459  break;
460  case 'order';
461  $query->setOrder($value);
462  break;
463  case 'limit':
464  $query->setLimit($value);
465  break;
466  case 'offset':
467  $query->setOffset($value);
468  break;
469  case 'count_total':
470  $query->countTotal($value);
471  break;
472  case 'runtime':
473  foreach ($value as $name => $fieldInfo)
474  {
475  $query->registerRuntimeField($name, $fieldInfo);
476  }
477  break;
478  case 'data_doubling':
479  if($value)
480  {
481  $query->enableDataDoubling();
482  }
483  else
484  {
485  $query->disableDataDoubling();
486  }
487  break;
488  case 'cache':
489  $query->setCacheTtl($value["ttl"]);
490  if(isset($value["cache_joins"]))
491  {
492  $query->cacheJoins($value["cache_joins"]);
493  }
494  break;
495  default:
496  throw new Main\ArgumentException("Unknown parameter: ".$param, $param);
497  }
498  }
499 
500  return $query->exec();
501  }
502 
503  /**
504  * Performs COUNT query on entity and returns the result.
505  *
506  * @param array|Filter $filter
507  * @param array $cache An array of cache options
508  * "ttl" => integer indicating cache TTL
509  * @return int
510  * @throws Main\ObjectPropertyException
511  * @throws Main\SystemException
512  */
513  public static function getCount($filter = array(), array $cache = array())
514  {
515  $query = static::query();
516 
517  // new filter
518  $query->addSelect(new ExpressionField('CNT', 'COUNT(1)'));
519 
520  if ($filter instanceof Filter)
521  {
522  $query->where($filter);
523  }
524  else
525  {
526  $query->setFilter($filter);
527  }
528 
529  if(isset($cache["ttl"]))
530  {
531  $query->setCacheTtl($cache["ttl"]);
532  }
533 
534  $result = $query->exec()->fetch();
535 
536  return $result['CNT'];
537  }
538 
539  /**
540  * Creates and returns the Query object for the entity
541  *
542  * @return Query
543  * @throws Main\ArgumentException
544  * @throws Main\SystemException
545  */
546  public static function query()
547  {
548  $queryClass = static::getQueryClass();
549  return new $queryClass(static::getEntity());
550  }
551 
552  /**
553  * @param array $data
554  *
555  * @return array
556  * @throws Main\ArgumentException
557  * @throws Main\SystemException
558  */
559  protected static function replaceFieldName($data = array())
560  {
561  $entity = static::getEntity();
562  foreach ($data as $fieldName => $value)
563  {
564  /** @var ScalarField $field */
565  $field = $entity->getField($fieldName);
566  $columnName = $field->getColumnName();
567  if($columnName != $fieldName)
568  {
569  $data[$columnName] = $data[$fieldName];
570  unset($data[$fieldName]);
571  }
572  }
573 
574  return $data;
575  }
576 
577  /**
578  * @param $primary
579  * @param array $data
580  *
581  * @throws Main\ArgumentException
582  * @throws Main\SystemException
583  */
584  protected static function normalizePrimary(&$primary, $data = array())
585  {
586  $entity = static::getEntity();
587  $entity_primary = $entity->getPrimaryArray();
588 
589  if ($primary === null)
590  {
591  $primary = array();
592 
593  // extract primary from data array
594  foreach ($entity_primary as $key)
595  {
596  /** @var ScalarField $field */
597  $field = $entity->getField($key);
598  if ($field->isAutocomplete())
599  {
600  continue;
601  }
602 
603  if (!isset($data[$key]))
604  {
605  throw new Main\ArgumentException(sprintf(
606  'Primary `%s` was not found when trying to query %s row.', $key, $entity->getName()
607  ));
608  }
609 
610  $primary[$key] = $data[$key];
611  }
612  }
613  elseif (is_scalar($primary))
614  {
615  if (count($entity_primary) > 1)
616  {
617  throw new Main\ArgumentException(sprintf(
618  'Require multi primary {`%s`}, but one scalar value "%s" found when trying to query %s row.',
619  join('`, `', $entity_primary), $primary, $entity->getName()
620  ));
621  }
622 
623  $primary = array($entity_primary[0] => $primary);
624  }
625  }
626 
627  /**
628  * @param $primary
629  *
630  * @throws Main\ArgumentException
631  * @throws Main\SystemException
632  */
633  protected static function validatePrimary($primary)
634  {
635  $entity = static::getEntity();
636  if (is_array($primary))
637  {
638  if(empty($primary))
639  {
640  throw new Main\ArgumentException(sprintf(
641  'Empty primary found when trying to query %s row.', $entity->getName()
642  ));
643  }
644 
645  $entity_primary = $entity->getPrimaryArray();
646 
647  foreach (array_keys($primary) as $key)
648  {
649  if (!in_array($key, $entity_primary, true))
650  {
651  throw new Main\ArgumentException(sprintf(
652  'Unknown primary `%s` found when trying to query %s row.',
653  $key, $entity->getName()
654  ));
655  }
656  }
657  }
658  else
659  {
660  throw new Main\ArgumentException(sprintf(
661  'Unknown type of primary "%s" found when trying to query %s row.', gettype($primary), $entity->getName()
662  ));
663  }
664 
665  // primary values validation
666  foreach ($primary as $key => $value)
667  {
668  if (!is_scalar($value) && !($value instanceof Main\Type\Date))
669  {
670  throw new Main\ArgumentException(sprintf(
671  'Unknown value type "%s" for primary "%s" found when trying to query %s row.',
672  gettype($value), $key, $entity->getName()
673  ));
674  }
675  }
676  }
677 
678  /**
679  * Checks the data fields before saving to DB. Result stores in the $result object
680  *
681  * @param Result $result
682  * @param mixed $primary
683  * @param array $data
684  *
685  * @throws Main\ArgumentException
686  * @throws Main\SystemException
687  */
688  public static function checkFields(Result $result, $primary, array $data)
689  {
690  $entity = static::getEntity();
691  //checks required fields
692  foreach ($entity->getFields() as $field)
693  {
694  if ($field instanceof ScalarField && $field->isRequired())
695  {
696  $fieldName = $field->getName();
697  if (
698  (empty($primary) && (!isset($data[$fieldName]) || $field->isValueEmpty($data[$fieldName])))
699  || (!empty($primary) && isset($data[$fieldName]) && $field->isValueEmpty($data[$fieldName]))
700  )
701  {
702  $result->addError(new FieldError(
703  $field,
704  Loc::getMessage("MAIN_ENTITY_FIELD_REQUIRED", array("#FIELD#"=>$field->getTitle())),
706  ));
707  }
708  }
709  }
710 
711  // checks data - fieldname & type & strlen etc.
712  foreach ($data as $k => $v)
713  {
714  if ($entity->hasField($k))
715  {
716  $field = $entity->getField($k);
717 
718  }
719  else
720  {
721  throw new Main\ArgumentException(sprintf(
722  'Field `%s` not found in entity when trying to query %s row.',
723  $k, $entity->getName()
724  ));
725  }
726 
727  $field->validateValue($v, $primary, $data, $result);
728  }
729  }
730 
731  /**
732  * @param array $fields
733  * @param bool $setDefaultValues
734  * @param array $primary
735  *
736  * @return EntityObject
737  * @throws Main\ArgumentException
738  * @throws Main\SystemException
739  */
740  protected static function convertArrayToObject(&$fields, $setDefaultValues = false, $primary = null)
741  {
742  // extended data format
743  $data = null;
744 
745  if (isset($fields["fields"]) && is_array($fields["fields"]))
746  {
747  $data = $fields;
748  $fields = $data["fields"];
749  }
750 
751  // convert to object
752  if (isset($fields['__object']))
753  {
754  $object = $fields['__object'];
755  unset($fields['__object']);
756  }
757  else
758  {
759  $entity = static::getEntity();
760 
761  /** @var EntityObject $object */
762  if ($primary === null)
763  {
764  $object = $entity->createObject($setDefaultValues);
765 
766  foreach ($fields as $fieldName => $value)
767  {
768  // sometimes data array can be used for storing non-entity data
769  if ($entity->hasField($fieldName))
770  {
771  $object->sysSetValue($fieldName, $value);
772  }
773  }
774  }
775  else
776  {
777  $object = $entity->wakeUpObject($primary);
778 
779  foreach ($fields as $fieldName => $value)
780  {
781  // sometimes data array can be used for storing non-entity data
782  if ($entity->hasField($fieldName))
783  {
784  if ($entity->getField($fieldName) instanceof ScalarField && $entity->getField($fieldName)->isPrimary())
785  {
786  // ignore old primary
787  if (array_key_exists($fieldName, $primary) && $primary[$fieldName] == $value)
788  {
789  unset($fields[$fieldName]);
790  continue;
791  }
792 
793  // but prevent primary changing
794  trigger_error(sprintf(
795  'Primary of %s %s can not be changed. You can delete this row and add a new one',
796  static::getObjectClass(), Main\Web\Json::encode($object->primary)
797  ), E_USER_WARNING);
798 
799  continue;
800  }
801 
802  $object->sysSetValue($fieldName, $value);
803  }
804  }
805  }
806  }
807 
808  // auth context
809  if (isset($data['auth_context']))
810  {
811  $object->authContext = $data['auth_context'];
812  }
813 
814  return $object;
815  }
816 
817  /**
818  * @param EntityObject $object
819  * @param $ufdata
820  * @param \Bitrix\Main\ORM\Data\Result $result
821  */
822  protected static function checkUfFields($object, $ufdata, $result)
823  {
824  global $USER_FIELD_MANAGER, $APPLICATION;
825 
826  $userId = ($object->authContext && $object->authContext->getUserId())
827  ? $object->authContext->getUserId()
828  : false;
829 
830  $ufPrimary = ($object->sysGetState() === Main\ORM\Objectify\State::RAW)
831  ? false
832  : end($object->primary);
833 
834  if (!$USER_FIELD_MANAGER->CheckFields($object->entity->getUfId(), $ufPrimary, $ufdata, $userId))
835  {
836  if (is_object($APPLICATION) && $APPLICATION->getException())
837  {
838  $e = $APPLICATION->getException();
839  $result->addError(new EntityError($e->getString()));
840  $APPLICATION->resetException();
841  }
842  else
843  {
844  $result->addError(new EntityError("Unknown error while checking userfields"));
845  }
846  }
847  }
848 
849  /**
850  * Adds row to entity table
851  *
852  * @param array $data An array with fields like
853  * array(
854  * "fields" => array(
855  * "FIELD1" => "value1",
856  * "FIELD2" => "value2",
857  * ),
858  * "auth_context" => \Bitrix\Main\Authentication\Context object
859  * )
860  * or just a plain array of fields.
861  *
862  * @return AddResult Contains ID of inserted row
863  *
864  * @throws \Exception
865  */
866  public static function add(array $data)
867  {
868  global $USER_FIELD_MANAGER;
869 
870  // compatibility
871  $fields = $data;
872 
873  // prepare entity object for compatibility with new code
874  $object = static::convertArrayToObject($fields, true);
875 
876  $entity = static::getEntity();
877  $result = new AddResult();
878 
879  try
880  {
881  static::callOnBeforeAddEvent($object, $fields, $result);
882 
883  // actualize old-style fields array from object
884  $fields = $object->collectValues(Values::CURRENT, FieldTypeMask::SCALAR);
885 
886  // uf values
887  $ufdata = $object->collectValues(Values::CURRENT, FieldTypeMask::USERTYPE);
888 
889  // check data
890  static::checkFields($result, null, $fields);
891 
892  // check uf data
893  if (!empty($ufdata))
894  {
895  static::checkUfFields($object, $ufdata, $result);
896  }
897 
898  // check if there is still some data
899  if (!count($fields + $ufdata))
900  {
901  $result->addError(new EntityError("There is no data to add."));
902  }
903 
904  // return if any error
905  if (!$result->isSuccess(true))
906  {
907  return $result;
908  }
909 
910  //event on adding
911  self::callOnAddEvent($object, $fields, $ufdata);
912 
913  // use save modifiers
914  $fieldsToDb = $fields;
915 
916  foreach ($fieldsToDb as $fieldName => $value)
917  {
918  $field = $entity->getField($fieldName);
919  $fieldsToDb[$fieldName] = $field->modifyValueBeforeSave($value, $fields);
920  }
921 
922  // save data
923  $connection = $entity->getConnection();
924 
925  $tableName = $entity->getDBTableName();
926  $identity = $entity->getAutoIncrement();
927 
928  $dataReplacedColumn = static::replaceFieldName($fieldsToDb);
929  $id = $connection->add($tableName, $dataReplacedColumn, $identity);
930 
931  // build standard primary
932  $primary = null;
933 
934  if (!empty($id))
935  {
936  if (strlen($entity->getAutoIncrement()))
937  {
938  $primary = array($entity->getAutoIncrement() => $id);
939  static::normalizePrimary($primary);
940  }
941  else
942  {
943  // for those who did not set 'autocomplete' flag but wants to get id from result
944  $primary = array('ID' => $id);
945  }
946  }
947  else
948  {
949  static::normalizePrimary($primary, $fields);
950  }
951 
952  // fill result
953  $result->setPrimary($primary);
954  $result->setData($fields);
955  $result->setObject($object);
956 
957  foreach ($primary as $primaryName => $primaryValue)
958  {
959  $object->sysSetActual($primaryName, $primaryValue);
960  }
961 
962  // save uf data
963  if (!empty($ufdata))
964  {
965  $USER_FIELD_MANAGER->update($entity->getUfId(), end($primary), $ufdata);
966  }
967 
968  $entity->cleanCache();
969 
970  static::callOnAfterAddEvent($object, $fields, $id);
971  }
972  catch (\Exception $e)
973  {
974  // check result to avoid warning
975  $result->isSuccess();
976 
977  throw $e;
978  }
979 
980  return $result;
981  }
982 
983  /**
984  * @param $rows
985  * @param bool $ignoreEvents
986  *
987  * @return AddResult
988  * @throws Main\ArgumentException
989  * @throws Main\SystemException
990  */
991  public static function addMulti($rows, $ignoreEvents = false)
992  {
993  global $USER_FIELD_MANAGER;
994 
995  $rows = array_values($rows);
996  $forceSeparateQueries = false;
997 
998  if (!$ignoreEvents && count($rows) > 1 && strlen(static::getEntity()->getAutoIncrement()))
999  {
1000  $forceSeparateQueries = true;
1001 
1002  // change to warning
1003  trigger_error(
1004  'Multi-insert doesn\'t work with events as far as we can not get last inserted IDs that we need for the events. '.
1005  'Insert query was forced to multiple separate queries.',
1006  E_USER_NOTICE
1007  );
1008  }
1009 
1010  // prepare objects
1011  $objects = [];
1012 
1013  foreach ($rows as $k => &$row)
1014  {
1015  $objects[$k] = static::convertArrayToObject($row, true);
1016  }
1017 
1018  $entity = static::getEntity();
1019  $result = new AddResult();
1020 
1021  try
1022  {
1023  // call onBeforeEvent
1024  if (!$ignoreEvents)
1025  {
1026  foreach ($objects as $k => $object)
1027  {
1028  static::callOnBeforeAddEvent($object, $rows[$k], $result);
1029  }
1030  }
1031 
1032  // collect array data
1033  $allFields = [];
1034  $allUfData = [];
1035 
1036  foreach ($objects as $k => $object)
1037  {
1038  // actualize old-style fields array from object
1039  $allFields[$k] = $object->collectValues(Values::CURRENT, FieldTypeMask::SCALAR);
1040 
1041  // uf values
1042  $allUfData[$k] = $object->collectValues(Values::CURRENT, FieldTypeMask::USERTYPE);
1043  }
1044 
1045  // check data and uf
1046  foreach ($objects as $k => $object)
1047  {
1048  $fields = $allFields[$k];
1049  $ufdata = $allUfData[$k];
1050 
1051  // check data
1052  static::checkFields($result, null, $fields);
1053 
1054  // check uf data
1055  if (!empty($ufdata))
1056  {
1057  static::checkUfFields($object, $ufdata, $result);
1058  }
1059 
1060  // check if there is still some data
1061  if (!count($fields + $ufdata))
1062  {
1063  $result->addError(new EntityError("There is no data to add."));
1064  }
1065  }
1066 
1067  // return if any error in any row
1068  if (!$result->isSuccess(true))
1069  {
1070  return $result;
1071  }
1072 
1073  //event on adding
1074  if (!$ignoreEvents)
1075  {
1076  foreach ($objects as $k => $object)
1077  {
1078  $fields = $allFields[$k];
1079  $ufdata = $allUfData[$k];
1080 
1081  self::callOnAddEvent($object, $fields, $ufdata);
1082  }
1083  }
1084 
1085  // prepare sql
1086  $allSqlData = [];
1087 
1088  foreach ($allFields as $k => $fields)
1089  {
1090  // use save modifiers
1091  $fieldsToDb = $fields;
1092 
1093  foreach ($fieldsToDb as $fieldName => $value)
1094  {
1095  $field = $entity->getField($fieldName);
1096  $fieldsToDb[$fieldName] = $field->modifyValueBeforeSave($value, $fields);
1097  }
1098 
1099  $dataReplacedColumn = static::replaceFieldName($fieldsToDb);
1100 
1101  $allSqlData[$k] = $dataReplacedColumn;
1102  }
1103 
1104  // save data
1105  $connection = $entity->getConnection();
1106 
1107  $tableName = $entity->getDBTableName();
1108  $identity = $entity->getAutoIncrement();
1109  $ids = [];
1110 
1111  // multi insert on db level
1112  if ($forceSeparateQueries)
1113  {
1114  foreach ($allSqlData as $k => $sqlData)
1115  {
1116  // remember all ids
1117  $ids[$k] = $connection->add($tableName, $sqlData, $identity);
1118  }
1119  }
1120  else
1121  {
1122  $id = $connection->addMulti($tableName, $allSqlData, $identity);
1123  }
1124 
1125  if (count($allSqlData) > 1)
1126  {
1127  // id doesn't make sense when multiple inserts
1128  $id = null;
1129  }
1130  else
1131  {
1132  $object = $objects[0];
1133  $fields = $allFields[0];
1134 
1135  // build standard primary
1136  $primary = null;
1137 
1138  if (!empty($id))
1139  {
1140  if (strlen($entity->getAutoIncrement()))
1141  {
1142  $primary = array($entity->getAutoIncrement() => $id);
1143  static::normalizePrimary($primary);
1144  }
1145  else
1146  {
1147  // for those who did not set 'autocomplete' flag but want to get id from result
1148  $primary = array('ID' => $id);
1149  }
1150  }
1151  else
1152  {
1153  static::normalizePrimary($primary, $fields);
1154  }
1155 
1156  // fill result
1157  $result->setPrimary($primary);
1158  $result->setData($fields);
1159  $result->setObject($object);
1160  }
1161 
1162  // save uf data
1163  foreach ($allUfData as $ufdata)
1164  {
1165  if (!empty($ufdata))
1166  {
1167  $USER_FIELD_MANAGER->update($entity->getUfId(), end($primary), $ufdata);
1168  }
1169  }
1170 
1171  $entity->cleanCache();
1172 
1173  // after event
1174  if (!$ignoreEvents)
1175  {
1176  foreach ($objects as $k => $object)
1177  {
1178  $fields = $allFields[$k];
1179  $id = $forceSeparateQueries ? $ids[$k] : null;
1180 
1181  static::callOnAfterAddEvent($object, $fields, $id);
1182  }
1183  }
1184  }
1185  catch (\Exception $e)
1186  {
1187  // check result to avoid warning
1188  $result->isSuccess();
1189 
1190  throw $e;
1191  }
1192 
1193  return $result;
1194  }
1195 
1196  /**
1197  * Updates row in entity table by primary key
1198  *
1199  * @param mixed $primary
1200  * @param array $data An array with fields like
1201  * array(
1202  * "fields" => array(
1203  * "FIELD1" => "value1",
1204  * "FIELD2" => "value2",
1205  * ),
1206  * "auth_context" => \Bitrix\Main\Authentication\Context object
1207  * )
1208  * or just a plain array of fields.
1209  *
1210  * @return UpdateResult
1211  *
1212  * @throws \Exception
1213  */
1214  public static function update($primary, array $data)
1215  {
1216  global $USER_FIELD_MANAGER;
1217 
1218  // check primary
1219  static::normalizePrimary(
1220  $primary, isset($fields["fields"]) && is_array($data["fields"]) ? $data["fields"] : $data
1221  );
1222  static::validatePrimary($primary);
1223 
1224  // compatibility
1225  $fields = $data;
1226 
1227  /** @var EntityObject $object prepare entity object for compatibility with new code */
1228  $object = static::convertArrayToObject($fields, false, $primary);
1229 
1230  $entity = static::getEntity();
1231  $result = new UpdateResult();
1232 
1233  try
1234  {
1235  static::callOnBeforeUpdateEvent($object, $fields, $result);
1236 
1237  // actualize old-style fields array from object
1238  $fields = $object->collectValues(Values::CURRENT, FieldTypeMask::SCALAR);
1239 
1240  // uf values
1241  $ufdata = $object->collectValues(Values::CURRENT, FieldTypeMask::USERTYPE);
1242 
1243  // check data
1244  static::checkFields($result, $primary, $fields);
1245 
1246  // check uf data
1247  if (!empty($ufdata))
1248  {
1249  static::checkUfFields($object, $ufdata, $result);
1250  }
1251 
1252  // check if there is still some data
1253  if (!count($fields + $ufdata))
1254  {
1255  return $result;
1256  }
1257 
1258  // return if any error
1259  if (!$result->isSuccess(true))
1260  {
1261  return $result;
1262  }
1263 
1264  static::callOnUpdateEvent($object, $fields, $ufdata);
1265 
1266  // use save modifiers
1267  $fieldsToDb = $fields;
1268 
1269  foreach ($fieldsToDb as $fieldName => $value)
1270  {
1271  $field = $entity->getField($fieldName);
1272  $fieldsToDb[$fieldName] = $field->modifyValueBeforeSave($value, $fields);
1273  }
1274 
1275  // save data
1276  if (!empty($fieldsToDb))
1277  {
1278  $connection = $entity->getConnection();
1279  $helper = $connection->getSqlHelper();
1280 
1281  $tableName = $entity->getDBTableName();
1282 
1283  $dataReplacedColumn = static::replaceFieldName($fieldsToDb);
1284  $update = $helper->prepareUpdate($tableName, $dataReplacedColumn);
1285 
1286  $replacedPrimary = static::replaceFieldName($primary);
1287  $id = array();
1288  foreach ($replacedPrimary as $k => $v)
1289  {
1290  $id[] = $helper->prepareAssignment($tableName, $k, $v);
1291  }
1292  $where = implode(' AND ', $id);
1293 
1294  $sql = "UPDATE ".$helper->quote($tableName)." SET ".$update[0]." WHERE ".$where;
1295  $connection->queryExecute($sql, $update[1]);
1296 
1297  $result->setAffectedRowsCount($connection);
1298  }
1299 
1300  $result->setData($fields);
1301  $result->setPrimary($primary);
1302  $result->setObject($object);
1303 
1304  // save uf data
1305  if (!empty($ufdata))
1306  {
1307  $USER_FIELD_MANAGER->update($entity->getUfId(), end($primary), $ufdata);
1308  }
1309 
1310  $entity->cleanCache();
1311 
1312  // event after update
1313  static::callOnAfterUpdateEvent($object, $fields);
1314  }
1315  catch (\Exception $e)
1316  {
1317  // check result to avoid warning
1318  $result->isSuccess();
1319 
1320  throw $e;
1321  }
1322 
1323  return $result;
1324  }
1325 
1326  /**
1327  * @param array $primaries
1328  * @param array $data
1329  * @param bool $ignoreEvents
1330  *
1331  * @return UpdateResult
1332  * @throws Main\ArgumentException
1333  * @throws Main\SystemException
1334  */
1335  public static function updateMulti($primaries, $data, $ignoreEvents = false)
1336  {
1337  $entity = static::getEntity();
1338  $primaries = array_values($primaries);
1339 
1340  /** @var EntityObject[] $objects */
1341  $objects = [];
1342 
1343  foreach ($primaries as &$primary)
1344  {
1345  static::normalizePrimary($primary, $data);
1346  static::validatePrimary($primary);
1347 
1348  /** @var EntityObject $object */
1349  $object = $entity->wakeUpObject($primary);
1350 
1351  foreach ($data as $k => $v)
1352  {
1353  $object->set($k, $v);
1354  }
1355 
1356  $objects[] = $object;
1357  }
1358 
1359  $result = new UpdateResult;
1360 
1361  try
1362  {
1363  // before event
1364  if (!$ignoreEvents)
1365  {
1366  foreach ($objects as $object)
1367  {
1368  static::callOnBeforeUpdateEvent($object, $data, $result);
1369  }
1370  }
1371 
1372  // collect array data
1373  $allFields = [];
1374  $allUfData = [];
1375 
1376  foreach ($objects as $k => $object)
1377  {
1378  // actualize old-style fields array from object
1379  $allFields[$k] = $object->collectValues(Values::CURRENT, FieldTypeMask::SCALAR);
1380 
1381  // uf values
1382  $allUfData[$k] = $object->collectValues(Values::CURRENT, FieldTypeMask::USERTYPE);
1383  }
1384 
1385  // check data and uf
1386  foreach ($objects as $k => $object)
1387  {
1388  $fields = $allFields[$k];
1389  $ufdata = $allUfData[$k];
1390 
1391  // check data
1392  static::checkFields($result, $object->primary, $fields);
1393 
1394  // check uf data
1395  if (!empty($ufdata))
1396  {
1397  static::checkUfFields($object, $ufdata, $result);
1398  }
1399 
1400  // check if there is still some data
1401  if (!count($fields + $ufdata))
1402  {
1403  $result->addError(new EntityError("There is no data to add."));
1404  }
1405  }
1406 
1407  // return if any error in any row
1408  if (!$result->isSuccess(true))
1409  {
1410  return $result;
1411  }
1412 
1413  //event on adding
1414  if (!$ignoreEvents)
1415  {
1416  foreach ($objects as $k => $object)
1417  {
1418  $fields = $allFields[$k];
1419  $ufdata = $allUfData[$k];
1420 
1421  static::callOnUpdateEvent($object, $fields, $ufdata);
1422  }
1423  }
1424 
1425  // prepare sql
1426  $allSqlData = [];
1427 
1428  foreach ($allFields as $k => $fields)
1429  {
1430  // use save modifiers
1431  $fieldsToDb = $fields;
1432 
1433  foreach ($fieldsToDb as $fieldName => $value)
1434  {
1435  $field = $entity->getField($fieldName);
1436  $fieldsToDb[$fieldName] = $field->modifyValueBeforeSave($value, $fields);
1437  }
1438 
1439  $dataReplacedColumn = static::replaceFieldName($fieldsToDb);
1440 
1441  $allSqlData[$k] = $dataReplacedColumn;
1442  }
1443 
1444  // check if rows data are equal
1445  $areEqual = true;
1446 
1447  $dataSample = $allSqlData[0];
1448  asort($dataSample);
1449 
1450  foreach ($allSqlData as $data)
1451  {
1452  asort($data);
1453 
1454  if ($data !== $dataSample)
1455  {
1456  $areEqual = false;
1457  break;
1458  }
1459  }
1460 
1461  // save data
1462  $connection = $entity->getConnection();
1463  $helper = $connection->getSqlHelper();
1464  $tableName = $entity->getDBTableName();
1465 
1466  // save data
1467  if ($areEqual)
1468  {
1469  // one query
1470  $update = $helper->prepareUpdate($tableName, $dataSample);
1471  $where = [];
1472  $isSinglePrimary = (count($entity->getPrimaryArray()) == 1);
1473 
1474  foreach ($allSqlData as $k => $data)
1475  {
1476  $replacedPrimary = static::replaceFieldName($objects[$k]->primary);
1477 
1478  if ($isSinglePrimary)
1479  {
1480  // for single primary IN is better
1481  $primaryName = key($replacedPrimary);
1482  $primaryValue = current($replacedPrimary);
1483  $tableField = $entity->getConnection()->getTableField($tableName, $primaryName);
1484 
1485  $where[] = $helper->convertToDb($primaryValue, $tableField);
1486  }
1487  else
1488  {
1489  $id = [];
1490 
1491  foreach ($replacedPrimary as $primaryName => $primaryValue)
1492  {
1493  $id[] = $helper->prepareAssignment($tableName, $primaryName, $primaryValue);
1494  }
1495  $where[] = implode(' AND ', $id);
1496  }
1497  }
1498 
1499  if ($isSinglePrimary)
1500  {
1501  $where = $helper->quote($entity->getPrimary()).' IN ('.join(', ', $where).')';
1502  }
1503  else
1504  {
1505  $where = '('.join(') OR (', $where).')';
1506  }
1507 
1508  $sql = "UPDATE ".$helper->quote($tableName)." SET ".$update[0]." WHERE ".$where;
1509  $connection->queryExecute($sql, $update[1]);
1510 
1511  $result->setAffectedRowsCount($connection);
1512  }
1513  else
1514  {
1515  // query for each row
1516  foreach ($allSqlData as $k => $dataReplacedColumn)
1517  {
1518  $update = $helper->prepareUpdate($tableName, $dataReplacedColumn);
1519 
1520  $replacedPrimary = static::replaceFieldName($objects[$k]->primary);
1521 
1522  $id = [];
1523 
1524  foreach ($replacedPrimary as $primaryName => $primaryValue)
1525  {
1526  $id[] = $helper->prepareAssignment($tableName, $primaryName, $primaryValue);
1527  }
1528  $where = implode(' AND ', $id);
1529 
1530  $sql = "UPDATE ".$helper->quote($tableName)." SET ".$update[0]." WHERE ".$where;
1531  $connection->queryExecute($sql, $update[1]);
1532 
1533  $result->setAffectedRowsCount($connection);
1534  }
1535  }
1536 
1537  // doesn't make sense for multiple rows
1538  $result->setData($dataSample);
1539 
1540  if (count($allSqlData) == 1)
1541  {
1542  $result->setPrimary($objects[0]->primary);
1543  $result->setObject($objects[0]);
1544  }
1545 
1546  // save uf data
1547  foreach ($allUfData as $ufdata)
1548  {
1549  if (!empty($ufdata))
1550  {
1551  global $USER_FIELD_MANAGER;
1552  $USER_FIELD_MANAGER->update($entity->getUfId(), end($primary), $ufdata);
1553  }
1554  }
1555 
1556  $entity->cleanCache();
1557 
1558  // event after update
1559  if (!$ignoreEvents)
1560  {
1561  foreach ($objects as $k => $object)
1562  {
1563  $fields = $allFields[$k];
1564 
1565  static::callOnAfterUpdateEvent($object, $fields);
1566  }
1567  }
1568  }
1569  catch (\Exception $e)
1570  {
1571  // check result to avoid warning
1572  $result->isSuccess();
1573 
1574  throw $e;
1575  }
1576 
1577  return $result;
1578  }
1579 
1580  /**
1581  * Deletes row in entity table by primary key
1582  *
1583  * @param mixed $primary
1584  *
1585  * @return DeleteResult
1586  *
1587  * @throws \Exception
1588  */
1589  public static function delete($primary)
1590  {
1591  global $USER_FIELD_MANAGER;
1592 
1593  // check primary
1594  static::normalizePrimary($primary);
1595  static::validatePrimary($primary);
1596 
1597  $entity = static::getEntity();
1598  $result = new DeleteResult();
1599 
1600  try
1601  {
1602  //event before delete
1603  static::callOnBeforeDeleteEvent($primary, $entity, $result);
1604 
1605  // return if any error
1606  if (!$result->isSuccess(true))
1607  {
1608  return $result;
1609  }
1610 
1611  //event on delete
1612  static::callOnDeleteEvent($primary, $entity);
1613 
1614  // delete
1615  $connection = $entity->getConnection();
1616  $helper = $connection->getSqlHelper();
1617 
1618  $tableName = $entity->getDBTableName();
1619 
1620  $replacedPrimary = static::replaceFieldName($primary);
1621  $id = array();
1622  foreach ($replacedPrimary as $k => $v)
1623  {
1624  $id[] = $helper->prepareAssignment($tableName, $k, $v);
1625  }
1626  $where = implode(' AND ', $id);
1627 
1628  $sql = "DELETE FROM ".$helper->quote($tableName)." WHERE ".$where;
1629  $connection->queryExecute($sql);
1630 
1631  // delete uf data
1632  if ($entity->getUfId())
1633  {
1634  $USER_FIELD_MANAGER->delete($entity->getUfId(), end($primary));
1635  }
1636 
1637  $entity->cleanCache();
1638 
1639  //event after delete
1640  static::callOnAfterDeleteEvent($primary, $entity);
1641  }
1642  catch (\Exception $e)
1643  {
1644  // check result to avoid warning
1645  $result->isSuccess();
1646 
1647  throw $e;
1648  }
1649 
1650  return $result;
1651  }
1652 
1653  /**
1654  * @param EntityObject $object
1655  * @param $fields
1656  * @param $result
1657  */
1658  protected static function callOnBeforeAddEvent($object, $fields, $result)
1659  {
1660  //event before adding
1661  $event = new Event($object->entity, self::EVENT_ON_BEFORE_ADD, [
1662  'fields' => $fields,
1663  'object' => $object
1664  ]);
1665 
1666  $event->send();
1667  $event->getErrors($result);
1668  $event->mergeObjectFields($object);
1669 
1670  //event before adding (modern with namespace)
1671  $event = new Event($object->entity, self::EVENT_ON_BEFORE_ADD, [
1672  'fields' => $fields,
1673  'object' => $object
1674  ], true);
1675 
1676  $event->send();
1677  $event->getErrors($result);
1678  $event->mergeObjectFields($object);
1679  }
1680 
1681  /**
1682  * @param $object
1683  * @param $fields
1684  * @param $ufdata
1685  */
1686  protected static function callOnAddEvent($object, $fields, $ufdata)
1687  {
1688  $event = new Event($object->entity, self::EVENT_ON_ADD, [
1689  'fields' => $fields + $ufdata,
1690  'object' => clone $object
1691  ]);
1692  $event->send();
1693 
1694  //event on adding (modern with namespace)
1695  $event = new Event($object->entity, self::EVENT_ON_ADD, [
1696  'fields' => $fields + $ufdata,
1697  'object' => clone $object
1698  ], true);
1699  $event->send();
1700  }
1701 
1702  /**
1703  * @param EntityObject $object
1704  * @param array $fields
1705  * @param int $id
1706  */
1707  protected static function callOnAfterAddEvent($object, $fields, $id)
1708  {
1709  //event after adding
1710  $event = new Event($object->entity, self::EVENT_ON_AFTER_ADD, [
1711  'id' => $id,
1712  'fields' => $fields,
1713  'object' => clone $object
1714  ]);
1715  $event->send();
1716 
1717  //event after adding (modern with namespace)
1718  $event = new Event($object->entity, self::EVENT_ON_AFTER_ADD, [
1719  'id' => $id,
1720  'primary' => $object->primary,
1721  'fields' => $fields,
1722  'object' => clone $object
1723  ], true);
1724  $event->send();
1725  }
1726 
1727  /**
1728  * @param EntityObject $object
1729  * @param $fields
1730  * @param $result
1731  */
1732  protected static function callOnBeforeUpdateEvent($object, $fields, $result)
1733  {
1734  $event = new Event($object->entity, self::EVENT_ON_BEFORE_UPDATE, [
1735  'id' => $object->primary,
1736  'fields' => $fields,
1737  'object' => $object
1738  ]);
1739 
1740  $event->send();
1741  $event->getErrors($result);
1742  $event->mergeObjectFields($object);
1743 
1744  //event before update (modern with namespace)
1745  $event = new Event($object->entity, self::EVENT_ON_BEFORE_UPDATE, [
1746  'id' => $object->primary,
1747  'primary' => $object->primary,
1748  'fields' => $fields,
1749  'object' => $object
1750  ], true);
1751 
1752  $event->send();
1753  $event->getErrors($result);
1754  $event->mergeObjectFields($object);
1755  }
1756 
1757  /**
1758  * @param EntityObject $object
1759  * @param $fields
1760  * @param $ufdata
1761  */
1762  protected static function callOnUpdateEvent($object, $fields, $ufdata)
1763  {
1764  $event = new Event($object->entity, self::EVENT_ON_UPDATE, [
1765  'id' => $object->primary,
1766  'fields' => $fields + $ufdata,
1767  'object' => clone $object
1768  ]);
1769  $event->send();
1770 
1771  //event on update (modern with namespace)
1772  $event = new Event($object->entity, self::EVENT_ON_UPDATE, [
1773  'id' => $object->primary,
1774  'primary' => $object->primary,
1775  'fields' => $fields + $ufdata,
1776  'object' => clone $object
1777  ], true);
1778  $event->send();
1779  }
1780 
1781  /**
1782  * @param EntityObject $object
1783  * @param $fields
1784  */
1785  protected static function callOnAfterUpdateEvent($object, $fields)
1786  {
1787  $event = new Event($object->entity, self::EVENT_ON_AFTER_UPDATE, [
1788  'id' => $object->primary,
1789  'fields' => $fields,
1790  'object' => clone $object
1791  ]);
1792  $event->send();
1793 
1794  //event after update (modern with namespace)
1795  $event = new Event($object->entity, self::EVENT_ON_AFTER_UPDATE, [
1796  'id' => $object->primary,
1797  'primary' => $object->primary,
1798  'fields' => $fields,
1799  'object' => clone $object
1800  ], true);
1801  $event->send();
1802  }
1803 
1804  /**
1805  * @param $primary
1806  * @param $entity
1807  * @param $result
1808  */
1809  protected static function callOnBeforeDeleteEvent($primary, $entity, $result)
1810  {
1811  $event = new Event($entity, self::EVENT_ON_BEFORE_DELETE, array("id" => $primary));
1812  $event->send();
1813  $event->getErrors($result);
1814 
1815  //event before delete (modern with namespace)
1816  $event = new Event($entity, self::EVENT_ON_BEFORE_DELETE, array("id" => $primary, "primary" => $primary), true);
1817  $event->send();
1818  $event->getErrors($result);
1819  }
1820 
1821  /**
1822  * @param $primary
1823  * @param $entity
1824  */
1825  protected static function callOnDeleteEvent($primary, $entity)
1826  {
1827  $event = new Event($entity, self::EVENT_ON_DELETE, array("id" => $primary));
1828  $event->send();
1829 
1830  //event on delete (modern with namespace)
1831  $event = new Event($entity, self::EVENT_ON_DELETE, array("id" => $primary, "primary" => $primary), true);
1832  $event->send();
1833  }
1834 
1835  /**
1836  * @param $primary
1837  * @param $entity
1838  */
1839  protected static function callOnAfterDeleteEvent($primary, $entity)
1840  {
1841  $event = new Event($entity, self::EVENT_ON_AFTER_DELETE, array("id" => $primary));
1842  $event->send();
1843 
1844  //event after delete (modern with namespace)
1845  $event = new Event($entity, self::EVENT_ON_AFTER_DELETE, array("id" => $primary, "primary" => $primary), true);
1846  $event->send();
1847  }
1848 
1849  /**
1850  * Sets a flag indicating crypto support for a field.
1851  *
1852  * @param string $field
1853  * @param string $table
1854  * @param bool $mode
1855  *
1856  * @throws Main\ArgumentNullException
1857  * @throws Main\ArgumentOutOfRangeException
1858  */
1859  public static function enableCrypto($field, $table = null, $mode = true)
1860  {
1861  if($table === null)
1862  {
1863  $table = static::getTableName();
1864  }
1865  $options = array();
1866  $optionString = Main\Config\Option::get("main", "~crypto_".$table);
1867  if($optionString <> '')
1868  {
1869  $options = unserialize($optionString);
1870  }
1871  $options[strtoupper($field)] = $mode;
1872  Main\Config\Option::set("main", "~crypto_".$table, serialize($options));
1873  }
1874 
1875  /**
1876  * Returns true if crypto is enabled for a field.
1877  *
1878  * @param string $field
1879  * @param string $table
1880  *
1881  * @return bool
1882  * @throws Main\ArgumentNullException
1883  * @throws Main\ArgumentOutOfRangeException
1884  */
1885  public static function cryptoEnabled($field, $table = null)
1886  {
1887  if($table === null)
1888  {
1889  $table = static::getTableName();
1890  }
1891  $optionString = Main\Config\Option::get("main", "~crypto_".$table);
1892  if($optionString <> '')
1893  {
1894  $field = strtoupper($field);
1895  $options = unserialize($optionString);
1896  if(isset($options[$field]) && $options[$field] === true)
1897  {
1898  return true;
1899  }
1900  }
1901  return false;
1902  }
1903 
1904  /*
1905  An inheritor class can define the event handlers for own events.
1906  Why? To prevent from rewriting the add/update/delete functions.
1907  These handlers are triggered in the Bitrix\Main\ORM\Event::send() function
1908  */
1909  public static function onBeforeAdd(Event $event){}
1910  public static function onAdd(Event $event){}
1911  public static function onAfterAdd(Event $event){}
1912  public static function onBeforeUpdate(Event $event){}
1913  public static function onUpdate(Event $event){}
1914  public static function onAfterUpdate(Event $event){}
1915  public static function onBeforeDelete(Event $event){}
1916  public static function onDelete(Event $event){}
1917  public static function onAfterDelete(Event $event){}
1918 }
Bitrix\Main\ORM\Data\DataManager\callOnBeforeDeleteEvent
static callOnBeforeDeleteEvent($primary, $entity, $result)
Definition: main/lib/orm/data/datamanager.php:1809
Bitrix\Main\Localization\Loc\getMessage
static getMessage($code, $replace=null, $language=null)
Returns translation by message code.
Definition: loc.php:29
Bitrix\Main\ORM\Data\DataManager\getById
static getById($id)
Returns selection by entity's primary key.
Definition: main/lib/orm/data/datamanager.php:374
Bitrix\Main\ORM\Data\DataManager\addMulti
static addMulti($rows, $ignoreEvents=false)
Definition: main/lib/orm/data/datamanager.php:991
Bitrix\Main\ORM\Data\DataManager\getRow
static getRow(array $parameters)
Returns one row (or null) by parameters for getList()
Definition: main/lib/orm/data/datamanager.php:407
Bitrix\Forum\Internals\getInstance
static getInstance($object)
Definition: forum/lib/internals/entityfabric.php:43
Bitrix\Main\ORM\Data\DataManager\callOnAfterAddEvent
static callOnAfterAddEvent($object, $fields, $id)
Definition: main/lib/orm/data/datamanager.php:1707
Bitrix\Main\ORM\Data\DataManager\callOnUpdateEvent
static callOnUpdateEvent($object, $fields, $ufdata)
Definition: main/lib/orm/data/datamanager.php:1762
Bitrix\Main\ORM\Data\DataManager
Base entity data manager.
Definition: main/lib/orm/data/datamanager.php:32
Bitrix\Main\ORM\Data\DataManager\enableCrypto
static enableCrypto($field, $table=null, $mode=true)
Sets a flag indicating crypto support for a field.
Definition: main/lib/orm/data/datamanager.php:1859
Bitrix\Main\ORM\Data\DataManager\validatePrimary
static validatePrimary($primary)
Definition: main/lib/orm/data/datamanager.php:633
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_BEFORE_DELETE
const EVENT_ON_BEFORE_DELETE
Definition: main/lib/orm/data/datamanager.php:40
Bitrix\Main\ORM\Data\UpdateResult
Definition: updateresult.php:13
Bitrix\Main\ORM\Data\DataManager\wakeUpObject
static wakeUpObject($row)
Definition: main/lib/orm/data/datamanager.php:266
Bitrix\Main\ORM\Data\DataManager\replaceFieldName
static replaceFieldName($data=array())
Definition: main/lib/orm/data/datamanager.php:559
Bitrix\Main\ORM\Data\DataManager\add
static add(array $data)
Adds row to entity table.
Definition: main/lib/orm/data/datamanager.php:866
Bitrix\Main
Bitrix\Main\ORM\Data\DataManager\callOnAfterDeleteEvent
static callOnAfterDeleteEvent($primary, $entity)
Definition: main/lib/orm/data/datamanager.php:1839
Bitrix\Main\ORM\Data\DataManager\setDefaultScope
static setDefaultScope($query)
Definition: main/lib/orm/data/datamanager.php:314
Bitrix\Main\ORM\Data\DataManager\getObjectClass
static getObjectClass()
Returns class of Object for current entity.
Definition: main/lib/orm/data/datamanager.php:130
Bitrix\Main\ORM\Data\DataManager\getMap
static getMap()
Returns entity map definition.
Definition: main/lib/orm/data/datamanager.php:289
Bitrix\Main\ORM\Objectify\State\RAW
const RAW
Definition: main/lib/orm/objectify/state.php:18
Bitrix\Main\Config\Option\set
static set($moduleId, $name, $value="", $siteId="")
Sets an option value and saves it into a DB.
Definition: main/lib/config/option.php:238
Bitrix\Main\ORM\Data\DataManager\getObjectClassName
static getObjectClassName()
Returns class name (without namespace) of Object for current entity.
Definition: main/lib/orm/data/datamanager.php:145
Bitrix\Main\ORM\Data\DataManager\query
static query()
Creates and returns the Query object for the entity.
Definition: main/lib/orm/data/datamanager.php:546
Bitrix\Main\ORM\Data\DataManager\callOnAfterUpdateEvent
static callOnAfterUpdateEvent($object, $fields)
Definition: main/lib/orm/data/datamanager.php:1785
Bitrix\Main\ORM\Objectify\EntityObject
Definition: entityobject.php:47
Bitrix\Main\ORM\Fields\FieldError
Definition: fielderror.php:13
Bitrix\Main\ORM\Data\DataManager\checkFields
static checkFields(Result $result, $primary, array $data)
Checks the data fields before saving to DB.
Definition: main/lib/orm/data/datamanager.php:688
Bitrix\Main\ORM\Data\DataManager\callOnAddEvent
static callOnAddEvent($object, $fields, $ufdata)
Definition: main/lib/orm/data/datamanager.php:1686
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_ADD
const EVENT_ON_ADD
Definition: main/lib/orm/data/datamanager.php:35
Bitrix\Main\ORM\Data\DataManager\getTableName
static getTableName()
Returns DB table name for entity.
Definition: main/lib/orm/data/datamanager.php:102
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_AFTER_ADD
const EVENT_ON_AFTER_ADD
Definition: main/lib/orm/data/datamanager.php:36
Bitrix\Main\ORM\Objectify\Collection
Definition: main/lib/orm/objectify/collection.php:32
Bitrix\Main\ORM\Data\DataManager\getByPrimary
static getByPrimary($primary, array $parameters=array())
Returns selection by entity's primary key and optional parameters for getList()
Definition: main/lib/orm/data/datamanager.php:340
Bitrix\Main\Web\Json\encode
static encode($data, $options=null)
Returns a string containing the JSON representation of $data.
Definition: web/json.php:22
Bitrix\Main\ORM\Data\DataManager\updateMulti
static updateMulti($primaries, $data, $ignoreEvents=false)
Definition: main/lib/orm/data/datamanager.php:1335
Bitrix\Main\ORM\Fields\ScalarField
Definition: scalarfield.php:18
Bitrix\Main\ORM\Data\DataManager\onBeforeDelete
static onBeforeDelete(Event $event)
Definition: main/lib/orm/data/datamanager.php:1915
Bitrix\Main\ORM\Data
Definition: addresult.php:9
Bitrix\Main\Config\Option\get
static get($moduleId, $name, $default="", $siteId=false)
Returns a value of an option.
Definition: main/lib/config/option.php:29
Bitrix\Main\ORM\Data\DataManager\$collectionClass
static $collectionClass
Definition: main/lib/orm/data/datamanager.php:51
Bitrix\Main\ORM\Fields\ExpressionField
Definition: expressionfield.php:23
Bitrix\Main\ORM\Data\DataManager\onAfterDelete
static onAfterDelete(Event $event)
Definition: main/lib/orm/data/datamanager.php:1917
Bitrix\Main\Type
Definition: main/lib/type/collection.php:2
Bitrix\Main\ORM\Data\DataManager\convertArrayToObject
static convertArrayToObject(&$fields, $setDefaultValues=false, $primary=null)
Definition: main/lib/orm/data/datamanager.php:740
Bitrix\Main\ORM\Data\DataManager\onAdd
static onAdd(Event $event)
Definition: main/lib/orm/data/datamanager.php:1910
Bitrix\Main\ORM\Data\DataManager\onAfterAdd
static onAfterAdd(Event $event)
Definition: main/lib/orm/data/datamanager.php:1911
Bitrix\Main\ORM\Data\DataManager\callOnBeforeAddEvent
static callOnBeforeAddEvent($object, $fields, $result)
Definition: main/lib/orm/data/datamanager.php:1658
Bitrix\Main\ORM\Entity
Base entity.
Definition: main/lib/orm/entity.php:25
Bitrix\Main\ORM\Data\DataManager\onAfterUpdate
static onAfterUpdate(Event $event)
Definition: main/lib/orm/data/datamanager.php:1914
Bitrix\Main\ArgumentException
Exception is thrown when function argument is not valid.
Definition: main/lib/exception.php:33
Bitrix\Main\ORM\Query\Filter\ConditionTree
Definition: conditiontree.php:23
Bitrix\Main\Event
Definition: main/lib/event.php:4
Bitrix\Main\ORM\Data\DataManager\postInitialize
static postInitialize(Entity $entity)
Definition: main/lib/orm/data/datamanager.php:324
Bitrix\Main\ORM\Data\DataManager\$reservedWords
static $reservedWords
Definition: main/lib/orm/data/datamanager.php:54
Bitrix\Main\ORM\EntityError
Definition: entityerror.php:11
Bitrix\Main\ORM\Fields\FieldError\EMPTY_REQUIRED
const EMPTY_REQUIRED
Definition: fielderror.php:15
Bitrix\Main\ORM\Query\Query
Definition: main/lib/orm/query/query.php:112
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_AFTER_DELETE
const EVENT_ON_AFTER_DELETE
Definition: main/lib/orm/data/datamanager.php:42
Bitrix\Main\ORM\Objectify\Values\CURRENT
const CURRENT
Definition: values.php:19
Bitrix\Main\ORM\Data\DataManager\isUtm
static isUtm()
Definition: main/lib/orm/data/datamanager.php:304
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_UPDATE
const EVENT_ON_UPDATE
Definition: main/lib/orm/data/datamanager.php:38
Bitrix\Main\ORM\Data\DataManager\getUfId
static getUfId()
Definition: main/lib/orm/data/datamanager.php:294
Bitrix\Main\ORM\Data\DataManager\$entity
static $entity
Definition: main/lib/orm/data/datamanager.php:45
Bitrix\Main\ORM\Data\DataManager\getObjectParentClass
static getObjectParentClass()
Definition: main/lib/orm/data/datamanager.php:206
Bitrix\Main\ORM\Data\DataManager\getCollectionClass
static getCollectionClass()
Returns class of Object collection for current entity.
Definition: main/lib/orm/data/datamanager.php:169
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_AFTER_UPDATE
const EVENT_ON_AFTER_UPDATE
Definition: main/lib/orm/data/datamanager.php:39
Bitrix\Main\ORM\Fields\FieldTypeMask\USERTYPE
const USERTYPE
Definition: fieldtypemask.php:19
Bitrix\Main\ORM\Data\DataManager\getRowById
static getRowById($id)
Returns one row (or null) by entity's primary key.
Definition: main/lib/orm/data/datamanager.php:389
Bitrix\Main\Localization\Loc
Definition: loc.php:10
Bitrix\Main\ORM\Fields\FieldTypeMask
Definition: fieldtypemask.php:15
Bitrix\Main\Type\Date
Definition: main/lib/type/date.php:7
Bitrix\Main\ORM\Data\DataManager\checkUfFields
static checkUfFields($object, $ufdata, $result)
Definition: main/lib/orm/data/datamanager.php:822
Bitrix\Main\ORM\Data\DataManager\onDelete
static onDelete(Event $event)
Definition: main/lib/orm/data/datamanager.php:1916
Bitrix\Main\ORM\Data\DataManager\getObjectClassByDataClass
static getObjectClassByDataClass($dataClass)
Definition: main/lib/orm/data/datamanager.php:151
Bitrix\Main\ORM\Data\DataManager\createCollection
static createCollection()
Definition: main/lib/orm/data/datamanager.php:252
Bitrix\Main\ORM\Data\DataManager\getQueryClass
static getQueryClass()
Definition: main/lib/orm/data/datamanager.php:222
Bitrix\Main\ORM\Fields\FieldTypeMask\SCALAR
const SCALAR
Definition: fieldtypemask.php:17
Bitrix\Main\ORM\Fields\ScalarField\isRequired
isRequired()
Definition: scalarfield.php:89
Bitrix\Main\ORM\Data\DataManager\getEntityClass
static getEntityClass()
Definition: main/lib/orm/data/datamanager.php:230
Bitrix\Main\Result\addError
addError(Error $error)
Adds the error.
Definition: main/lib/result.php:45
Bitrix\Main\ORM\Data\DataManager\callOnBeforeUpdateEvent
static callOnBeforeUpdateEvent($object, $fields, $result)
Definition: main/lib/orm/data/datamanager.php:1732
Bitrix\Main\ORM\Data\DataManager\cryptoEnabled
static cryptoEnabled($field, $table=null)
Returns true if crypto is enabled for a field.
Definition: main/lib/orm/data/datamanager.php:1885
Bitrix\Main\ORM\Data\DataManager\getTitle
static getTitle()
Definition: main/lib/orm/data/datamanager.php:120
Bitrix\Main\ORM\Data\DataManager\wakeUpCollection
static wakeUpCollection($rows)
Definition: main/lib/orm/data/datamanager.php:280
Bitrix\Main\ORM\Data\DataManager\update
static update($primary, array $data)
Updates row in entity table by primary key.
Definition: main/lib/orm/data/datamanager.php:1214
Bitrix\Main\ORM\Data\DataManager\getCollectionClassByDataClass
static getCollectionClassByDataClass($dataClass)
Definition: main/lib/orm/data/datamanager.php:190
Bitrix\Main\ORM\Data\DataManager\onBeforeUpdate
static onBeforeUpdate(Event $event)
Definition: main/lib/orm/data/datamanager.php:1912
Bitrix\Main\ORM\Data\DataManager\isUts
static isUts()
Definition: main/lib/orm/data/datamanager.php:299
Bitrix\Main\ORM\Data\DataManager\getEntity
static getEntity()
Returns entity object.
Definition: main/lib/orm/data/datamanager.php:75
Bitrix\Main\Localization\Loc\loadMessages
static loadMessages($file)
Loads language messages for specified file in a lazy way.
Definition: loc.php:67
Bitrix\Main\ORM\Data\DataManager\callOnDeleteEvent
static callOnDeleteEvent($primary, $entity)
Definition: main/lib/orm/data/datamanager.php:1825
Bitrix\Sender\Connector\Filter
const Filter
Definition: resultview.php:22
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_DELETE
const EVENT_ON_DELETE
Definition: main/lib/orm/data/datamanager.php:41
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_BEFORE_ADD
const EVENT_ON_BEFORE_ADD
Definition: main/lib/orm/data/datamanager.php:34
Bitrix\Main\ORM\Data\DataManager\getList
static getList(array $parameters=array())
Executes the query and returns selection by parameters of the query.
Definition: main/lib/orm/data/datamanager.php:438
Bitrix\Main\ORM\Data\Result
Definition: main/lib/orm/data/result.php:15
Bitrix\Main\ORM\Data\DataManager\onUpdate
static onUpdate(Event $event)
Definition: main/lib/orm/data/datamanager.php:1913
Bitrix\Main\ORM\Data\DataManager\getCollectionClassName
static getCollectionClassName()
Returns class name (without namespace) of Object collection for current entity.
Definition: main/lib/orm/data/datamanager.php:184
Bitrix\Main\ORM\Data\DataManager\EVENT_ON_BEFORE_UPDATE
const EVENT_ON_BEFORE_UPDATE
Definition: main/lib/orm/data/datamanager.php:37
Bitrix\Main\ORM\Objectify\Values
Definition: values.php:16
Bitrix\Main\ORM\Data\DataManager\getCount
static getCount($filter=array(), array $cache=array())
Performs COUNT query on entity and returns the result.
Definition: main/lib/orm/data/datamanager.php:513
Bitrix\Main\ORM\Data\DataManager\$objectClass
static $objectClass
Definition: main/lib/orm/data/datamanager.php:48
Bitrix\Main\ORM\Data\DataManager\createObject
static createObject($setDefaultValues=true)
Definition: main/lib/orm/data/datamanager.php:242
Bitrix\Main\ORM\Data\DataManager\getCollectionParentClass
static getCollectionParentClass()
Definition: main/lib/orm/data/datamanager.php:214
Bitrix\Main\ORM\Data\DataManager\unsetEntity
static unsetEntity($class)
Definition: main/lib/orm/data/datamanager.php:87
Bitrix\Main\ORM\Data\DataManager\normalizePrimary
static normalizePrimary(&$primary, $data=array())
Definition: main/lib/orm/data/datamanager.php:584
Bitrix\Main\ORM\Data\DataManager\getConnectionName
static getConnectionName()
Returns connection name for entity.
Definition: main/lib/orm/data/datamanager.php:112
Bitrix\Main\ORM\Data\AddResult
Definition: addresult.php:11
Bitrix\Main\ORM\Data\DataManager\onBeforeAdd
static onBeforeAdd(Event $event)
Definition: main/lib/orm/data/datamanager.php:1909
Bitrix\Main\ORM\Data\DeleteResult
Definition: deleteresult.php:11