3namespace Bitrix\Main\ORM\Annotations;
5use Bitrix\Main\Authentication\Context;
6use Bitrix\Main\DB\SqlExpression;
8use Bitrix\Main\ORM\Data\AddResult;
9use Bitrix\Main\ORM\Data\DataManager;
10use Bitrix\Main\ORM\Data\Result;
11use Bitrix\Main\ORM\Data\UpdateResult;
12use Bitrix\Main\ORM\Entity;
13use Bitrix\Main\ORM\Fields\ExpressionField;
14use Bitrix\Main\ORM\Fields\FieldTypeMask;
15use Bitrix\Main\ORM\Fields\Relations\ManyToMany;
16use Bitrix\Main\ORM\Fields\Relations\OneToMany;
17use Bitrix\Main\ORM\Fields\Relations\Reference;
18use Bitrix\Main\ORM\Fields\ScalarField;
19use Bitrix\Main\ORM\Fields\UserTypeField;
20use Bitrix\Main\ORM\Objectify\Collection;
21use Bitrix\Main\ORM\Objectify\State;
22use Bitrix\Main\ORM\Query\Query;
23use Bitrix\Main\Text\StringHelper;
24use Bitrix\Main\Type\Dictionary;
41 public static function annotateEntity(
Entity $entity, $ufOnly =
false, $separateTable =
false)
43 $entityNamespace = trim(
$entity->getNamespace(),
'\\');
47 $objectClassName =
$entity->getObjectClassName();
51 $collectionClassName =
$entity->getCollectionClassName();
58 $code[] =
"namespace {$entityNamespace} {";
60 $code[] =
"\t * {$objectClassName}";
61 $code[] =
"\t * @see {$dataClass}";
63 $code[] =
"\t * Custom methods:";
64 $code[] =
"\t * ---------------";
69 foreach (
$entity->getFields() as $field)
71 $objectFieldCode = [];
72 $collectionFieldCode = [];
83 [$objectFieldCode, $collectionFieldCode] = static::annotateScalarField($field);
87 [$objectFieldCode, $collectionFieldCode] = static::annotateUserType($field);
91 [$objectFieldCode, $collectionFieldCode] = static::annotateExpression($field);
95 [$objectFieldCode, $collectionFieldCode] = static::annotateReference($field);
99 [$objectFieldCode, $collectionFieldCode] = static::annotateOneToMany($field);
103 [$objectFieldCode, $collectionFieldCode] = static::annotateManyToMany($field);
106 $objectCode = array_merge($objectCode, $objectFieldCode);
107 $collectionCode = array_merge($collectionCode, $collectionFieldCode);
109 catch (\Exception $e)
111 $exceptions[] = new \Exception(
112 "Can not annotate `{$entity->getFullName()}.{$field->getName()}` field", 0, $e
118 if ($ufOnly && empty($objectCode))
129 $code[] =
"\t * Common methods:";
130 $code[] =
"\t * ---------------";
132 $code[] =
"\t * @property-read \\".Entity::class.
" \$entity";
133 $code[] =
"\t * @property-read array \$primary";
134 $code[] =
"\t * @property-read int \$state @see \\".State::class;
135 $code[] =
"\t * @property-read \\".Dictionary::class.
" \$customData";
136 $code[] =
"\t * @property \\".Context::class.
" \$authContext";
137 $code[] =
"\t * @method mixed get(\$fieldName)";
138 $code[] =
"\t * @method mixed remindActual(\$fieldName)";
139 $code[] =
"\t * @method mixed require(\$fieldName)";
140 $code[] =
"\t * @method bool has(\$fieldName)";
141 $code[] =
"\t * @method bool isFilled(\$fieldName)";
142 $code[] =
"\t * @method bool isChanged(\$fieldName)";
143 $code[] =
"\t * @method {$objectClass} set(\$fieldName, \$value)";
144 $code[] =
"\t * @method {$objectClass} reset(\$fieldName)";
145 $code[] =
"\t * @method {$objectClass} unset(\$fieldName)";
146 $code[] =
"\t * @method void addTo(\$fieldName, \$value)";
147 $code[] =
"\t * @method void removeFrom(\$fieldName, \$value)";
148 $code[] =
"\t * @method void removeAll(\$fieldName)";
149 $code[] =
"\t * @method \\".Result::class.
" delete()";
150 $code[] =
"\t * @method mixed fill(\$fields = \\".FieldTypeMask::class.
"::ALL) flag or array of field names";
151 $code[] =
"\t * @method mixed[] collectValues(\$valuesType = \Bitrix\Main\ORM\Objectify\Values::ALL, \$fieldsMask = \Bitrix\Main\ORM\Fields\FieldTypeMask::ALL)";
152 $code[] =
"\t * @method \\".AddResult::class.
"|\\".UpdateResult::class.
"|\\".Result::class.
" save()";
153 $code[] =
"\t * @method static {$objectClass} wakeUp(\$data)";
160 $code[] =
"\tclass {$objectDefaultClassName} {";
161 $code[] =
"\t\t/* @var {$dataClass} */";
162 $code[] =
"\t\tstatic public \$dataClass = '{$dataClass}';";
164 $code[] =
"\t\t * @param bool|array \$setDefaultValues";
166 $code[] =
"\t\tpublic function __construct(\$setDefaultValues = true) {}";
181 $code[] =
"namespace {$entityNamespace} {";
183 $code[] =
"\t * {$collectionClassName}";
185 $code[] =
"\t * Custom methods:";
186 $code[] =
"\t * ---------------";
194 $code[] =
"\t * Common methods:";
195 $code[] =
"\t * ---------------";
197 $code[] =
"\t * @property-read \\".Entity::class.
" \$entity";
198 $code[] =
"\t * @method void add({$objectClass} \$object)";
199 $code[] =
"\t * @method bool has({$objectClass} \$object)";
200 $code[] =
"\t * @method bool hasByPrimary(\$primary)";
201 $code[] =
"\t * @method {$objectClass} getByPrimary(\$primary)";
202 $code[] =
"\t * @method {$objectClass}[] getAll()";
203 $code[] =
"\t * @method bool remove({$objectClass} \$object)";
204 $code[] =
"\t * @method void removeByPrimary(\$primary)";
205 $code[] =
"\t * @method array|\\".Collection::class.
"|null fill(\$fields = \\".FieldTypeMask::class.
"::ALL) flag or array of field names";
206 $code[] =
"\t * @method static {$collectionClass} wakeUp(\$data)";
207 $code[] =
"\t * @method \\".Result::class.
" save(\$ignoreEvents = false)";
208 $code[] =
"\t * @method void offsetSet() ArrayAccess";
209 $code[] =
"\t * @method void offsetExists() ArrayAccess";
210 $code[] =
"\t * @method void offsetUnset() ArrayAccess";
211 $code[] =
"\t * @method void offsetGet() ArrayAccess";
212 $code[] =
"\t * @method void rewind() Iterator";
213 $code[] =
"\t * @method {$objectClass} current() Iterator";
214 $code[] =
"\t * @method mixed key() Iterator";
215 $code[] =
"\t * @method void next() Iterator";
216 $code[] =
"\t * @method bool valid() Iterator";
217 $code[] =
"\t * @method int count() Countable";
218 $code[] =
"\t * @method {$collectionClass} merge(?{$collectionClass} \$collection)";
219 $code[] =
"\t * @method bool isEmpty()";
220 $code[] =
"\t * @method array collectValues(int \$valuesType = \Bitrix\Main\ORM\Objectify\Values::ALL, int \$fieldsMask = \Bitrix\Main\ORM\Fields\FieldTypeMask::ALL, bool \$recursive = false)";
225 $code[] =
"\tclass {$collectionDefaultClassName} implements \ArrayAccess, \Iterator, \Countable {";
226 $code[] =
"\t\t/* @var {$dataClass} */";
227 $code[] =
"\t\tstatic public \$dataClass = '{$dataClass}';";
244 $dataClassName =
$entity->getName().
'Table';
250 if (
$entity->getDataClass()::getQueryClass() !== Query::class)
252 $queryClassName =
'\\'.$entity->getDataClass()::getQueryClass();
253 $reflectionClass = new \ReflectionClass($queryClassName);
255 if ($reflectionClass->getNamespaceName() === $entityNamespace)
258 $queryClassName = $reflectionClass->getShortName();
263 $queryClassName = $eoQueryClassName;
266 $code[] =
"namespace {$entityNamespace} {";
274 $codeTable[] =
" * @method static {$queryClassName} query()";
275 $codeTable[] =
" * @method static {$resultClassName} getByPrimary(\$primary, array \$parameters = [])";
276 $codeTable[] =
" * @method static {$resultClassName} getById(\$id)";
277 $codeTable[] =
" * @method static {$resultClassName} getList(array \$parameters = [])";
278 $codeTable[] =
" * @method static {$entityClassName} getEntity()";
279 $codeTable[] =
" * @method static {$objectClass} createObject(\$setDefaultValues = true)";
280 $codeTable[] =
" * @method static {$collectionClass} createCollection()";
281 $codeTable[] =
" * @method static {$objectClass} wakeUpObject(\$row)";
282 $codeTable[] =
" * @method static {$collectionClass} wakeUpCollection(\$rows)";
287 foreach ($codeTable as
$i => $line)
289 $codeTable[
$i] =
"\t".$line;
294 $code[] =
"\tclass {$dataClassName} extends \\".DataManager::class.
" {}";
299 $code[] =
"\t * Common methods:";
300 $code[] =
"\t * ---------------";
302 $code[] =
"\t * @method {$resultClassName} exec()";
303 $code[] =
"\t * @method {$objectClass} fetchObject()";
304 $code[] =
"\t * @method {$collectionClass} fetchCollection()";
306 $customQueryMethodsCode = [];
311 if (str_starts_with(
$method,
'with'))
315 if ($reflectionMethod->isStatic())
320 foreach (array_slice($reflectionMethod->getParameters(), 1) as $parameter)
322 $arguments[] =
'$'.$parameter->getName();
325 $argumentsMeta = join(
', ', $arguments);
327 $customQueryMethodsCode[] =
"\t * @see {$dataClass}::{$method}()";
328 $customQueryMethodsCode[] =
"\t * @method self {$method}({$argumentsMeta})";
333 if (!empty($customQueryMethodsCode))
336 $code[] =
"\t * Custom methods:";
337 $code[] =
"\t * ---------------";
340 array_push(
$code, $customQueryMethodsCode);
344 $code[] =
"\tclass {$eoQueryClassName} extends \\".Query::class.
" {}";
348 $code[] =
"\t * @method {$objectClass} fetchObject()";
349 $code[] =
"\t * @method {$collectionClass} fetchCollection()";
351 $code[] =
"\tclass {$resultClassName} extends \\".\Bitrix\Main\ORM\Query\Result::class.
" {}";
355 $code[] =
"\t * @method {$objectClass} createObject(\$setDefaultValues = true)";
356 $code[] =
"\t * @method {$collectionClass} createCollection()";
357 $code[] =
"\t * @method {$objectClass} wakeUpObject(\$row)";
358 $code[] =
"\t * @method {$collectionClass} wakeUpCollection(\$rows)";
360 $code[] =
"\tclass {$entityClassName} extends \\".Entity::class.
" {}";
367 return join(
"\n",
$code);
372 join(
"\n", $codeTable),
379 public static function annotateScalarField(
ScalarField $field)
384 $getterDataType = $field->getGetterTypeHint();
385 $setterDataType = $field->getSetterTypeHint();
386 list($lName, $uName) = static::getFieldNameCamelCase($field->getName());
389 $collectionCode = [];
391 $objectCode[] =
"\t * @method {$getterDataType} get{$uName}()";
392 $objectCode[] =
"\t * @method {$objectClass} set{$uName}({$setterDataType}|\\".SqlExpression::class.
" \${$lName})";
394 $objectCode[] =
"\t * @method bool has{$uName}()";
395 $objectCode[] =
"\t * @method bool is{$uName}Filled()";
396 $objectCode[] =
"\t * @method bool is{$uName}Changed()";
398 $collectionCode[] =
"\t * @method {$getterDataType}[] get{$uName}List()";
400 if (!$field->isPrimary())
402 $objectCode[] =
"\t * @method {$getterDataType} remindActual{$uName}()";
403 $objectCode[] =
"\t * @method {$getterDataType} require{$uName}()";
405 $objectCode[] =
"\t * @method {$objectClass} reset{$uName}()";
406 $objectCode[] =
"\t * @method {$objectClass} unset{$uName}()";
408 $objectCode[] =
"\t * @method {$getterDataType} fill{$uName}()";
409 $collectionCode[] =
"\t * @method {$getterDataType}[] fill{$uName}()";
412 return [$objectCode, $collectionCode];
415 public static function annotateUserType(
UserTypeField $field)
421 $scalarFieldClass = $field->getValueType();
424 list($lName, $uName) = static::getFieldNameCamelCase($field->getName());
426 list($objectCode, $collectionCode) = static::annotateExpression($field);
429 $objectCode[] =
"\t * @method {$objectClass} set{$uName}({$dataType} \${$lName})";
431 $objectCode[] =
"\t * @method bool is{$uName}Changed()";
433 return [$objectCode, $collectionCode];
441 $scalarFieldClass = $field->getValueType();
443 list($lName, $uName) = static::getFieldNameCamelCase($field->getName());
446 $collectionCode = [];
448 $objectCode[] =
"\t * @method {$dataType} get{$uName}()";
449 $objectCode[] =
"\t * @method {$dataType} remindActual{$uName}()";
450 $objectCode[] =
"\t * @method {$dataType} require{$uName}()";
452 $objectCode[] =
"\t * @method bool has{$uName}()";
453 $objectCode[] =
"\t * @method bool is{$uName}Filled()";
455 $collectionCode[] =
"\t * @method {$dataType}[] get{$uName}List()";
457 $objectCode[] =
"\t * @method {$objectClass} unset{$uName}()";
459 $objectCode[] =
"\t * @method {$dataType} fill{$uName}()";
460 $collectionCode[] =
"\t * @method {$dataType}[] fill{$uName}()";
462 return [$objectCode, $collectionCode];
465 public static function annotateReference(
Reference $field)
467 if (!static::tryToFindEntity($field->getRefEntityName()))
474 $collectionDataType = $field->getRefEntity()->getCollectionClass();
476 $getterTypeHint = $field->getGetterTypeHint();
477 $setterTypeHint = $field->getSetterTypeHint();
479 list($lName, $uName) = static::getFieldNameCamelCase($field->getName());
482 $collectionCode = [];
484 $objectCode[] =
"\t * @method {$getterTypeHint} get{$uName}()";
485 $objectCode[] =
"\t * @method {$getterTypeHint} remindActual{$uName}()";
486 $objectCode[] =
"\t * @method {$getterTypeHint} require{$uName}()";
488 $objectCode[] =
"\t * @method {$objectClass} set{$uName}({$setterTypeHint} \$object)";
489 $objectCode[] =
"\t * @method {$objectClass} reset{$uName}()";
490 $objectCode[] =
"\t * @method {$objectClass} unset{$uName}()";
492 $objectCode[] =
"\t * @method bool has{$uName}()";
493 $objectCode[] =
"\t * @method bool is{$uName}Filled()";
494 $objectCode[] =
"\t * @method bool is{$uName}Changed()";
496 $collectionCode[] =
"\t * @method {$getterTypeHint}[] get{$uName}List()";
497 $collectionCode[] =
"\t * @method {$collectionClass} get{$uName}Collection()";
499 $objectCode[] =
"\t * @method {$getterTypeHint} fill{$uName}()";
500 $collectionCode[] =
"\t * @method {$collectionDataType} fill{$uName}()";
502 return [$objectCode, $collectionCode];
505 public static function annotateOneToMany(
OneToMany $field)
507 if (!static::tryToFindEntity($field->getRefEntityName()))
513 $collectionDataType = $field->getRefEntity()->getCollectionClass();
514 $objectVarName = lcfirst($field->getRefEntity()->getName());
516 $setterTypeHint = $field->getSetterTypeHint();
518 list($lName, $uName) = static::getFieldNameCamelCase($field->getName());
521 $collectionCode = [];
523 $objectCode[] =
"\t * @method {$collectionDataType} get{$uName}()";
524 $objectCode[] =
"\t * @method {$collectionDataType} require{$uName}()";
525 $objectCode[] =
"\t * @method {$collectionDataType} fill{$uName}()";
527 $objectCode[] =
"\t * @method bool has{$uName}()";
528 $objectCode[] =
"\t * @method bool is{$uName}Filled()";
529 $objectCode[] =
"\t * @method bool is{$uName}Changed()";
531 $objectCode[] =
"\t * @method void addTo{$uName}({$setterTypeHint} \${$objectVarName})";
532 $objectCode[] =
"\t * @method void removeFrom{$uName}({$setterTypeHint} \${$objectVarName})";
533 $objectCode[] =
"\t * @method void removeAll{$uName}()";
535 $objectCode[] =
"\t * @method {$objectClass} reset{$uName}()";
536 $objectCode[] =
"\t * @method {$objectClass} unset{$uName}()";
538 $collectionCode[] =
"\t * @method {$collectionDataType}[] get{$uName}List()";
539 $collectionCode[] =
"\t * @method {$collectionDataType} get{$uName}Collection()";
540 $collectionCode[] =
"\t * @method {$collectionDataType} fill{$uName}()";
542 return [$objectCode, $collectionCode];
545 public static function annotateManyToMany(
ManyToMany $field)
547 if (!static::tryToFindEntity($field->getRefEntityName()))
553 $collectionDataType = $field->getRefEntity()->getCollectionClass();
554 $objectVarName = lcfirst($field->getRefEntity()->getName());
556 $setterTypeHint = $field->getSetterTypeHint();
558 list($lName, $uName) = static::getFieldNameCamelCase($field->getName());
561 $collectionCode = [];
563 $objectCode[] =
"\t * @method {$collectionDataType} get{$uName}()";
564 $objectCode[] =
"\t * @method {$collectionDataType} require{$uName}()";
565 $objectCode[] =
"\t * @method {$collectionDataType} fill{$uName}()";
567 $objectCode[] =
"\t * @method bool has{$uName}()";
568 $objectCode[] =
"\t * @method bool is{$uName}Filled()";
569 $objectCode[] =
"\t * @method bool is{$uName}Changed()";
571 $objectCode[] =
"\t * @method void addTo{$uName}({$setterTypeHint} \${$objectVarName})";
572 $objectCode[] =
"\t * @method void removeFrom{$uName}({$setterTypeHint} \${$objectVarName})";
573 $objectCode[] =
"\t * @method void removeAll{$uName}()";
575 $objectCode[] =
"\t * @method {$objectClass} reset{$uName}()";
576 $objectCode[] =
"\t * @method {$objectClass} unset{$uName}()";
578 $collectionCode[] =
"\t * @method {$collectionDataType}[] get{$uName}List()";
579 $collectionCode[] =
"\t * @method {$collectionDataType} get{$uName}Collection()";
580 $collectionCode[] =
"\t * @method {$collectionDataType} fill{$uName}()";
582 return [$objectCode, $collectionCode];
585 public static function tryToFindEntity($entityClass)
589 if (!class_exists($entityClass))
592 $classParts = array_values(array_filter(
593 explode(
'\\', strtolower($entityClass))
596 if ($classParts[0] ==
'bitrix')
598 $moduleName = $classParts[1];
602 $moduleName = $classParts[0].
'.'.$classParts[1];
611 if ((
new \ReflectionClass($entityClass))->isAbstract())
619 protected static function getFieldNameCamelCase($fieldName)
621 $upperFirstName = StringHelper::snake2camel($fieldName);
622 $lowerFirstName = lcfirst($upperFirstName);
624 return [$lowerFirstName, $upperFirstName];
static includeModule($moduleName)
static normalizeEntityClass($entityName)
static getDefaultObjectClassName($entityName)
static getDefaultCollectionClassName($entityName)
const DEFAULT_OBJECT_PREFIX
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)