/** * @param TypeInterface $type */ public function buildType(TypeInterface $type) { $base_manager_class_name = Inflector::classify($type->getName()); $type_class_name = Inflector::classify(Inflector::singularize($type->getName())); $base_class_build_path = $this->getBuildPath() ? "{$this->getBuildPath()}/Manager/Base/{$base_manager_class_name}.php" : null; $result = []; $result[] = '<?php'; $result[] = ''; if ($this->getStructure()->getConfig('header_comment')) { $result = array_merge($result, explode("\n", $this->getStructure()->getConfig('header_comment'))); $result[] = ''; } if ($this->getStructure()->getNamespace()) { $base_class_namespace = $this->getStructure()->getNamespace() . '\\Manager\\Base'; $type_class_name = '\\' . ltrim($this->getStructure()->getNamespace(), '\\') . '\\' . $type_class_name; } else { $base_class_namespace = 'Manager\\Base'; } $result[] = 'namespace ' . $base_class_namespace . ';'; $result[] = ''; $result[] = '/**'; $result[] = ' * @package ' . $base_class_namespace; $result[] = ' */'; $interfaces = $traits = []; foreach ($type->getTraits() as $interface => $implementations) { if ($interface != '--just-paste-trait--') { $interfaces[] = '\\' . ltrim($interface, '\\'); } if (count($implementations)) { foreach ($implementations as $implementation) { $traits[] = '\\' . ltrim($implementation, '\\'); } } } $result[] = 'abstract class ' . $base_manager_class_name . ' extends \\ActiveCollab\\DatabaseObject\\Entity\\Manager'; $result[] = '{'; $result[] = ' /**'; $result[] = ' * Return type that this manager works with.'; $result[] = ' *'; $result[] = ' * @return string'; $result[] = ' */'; $result[] = ' public function getType()'; $result[] = ' {'; $result[] = ' return ' . var_export($type_class_name, true) . ';'; $result[] = ' }'; $result[] = '}'; $result[] = ''; $result = implode("\n", $result); if ($this->getBuildPath()) { file_put_contents($base_class_build_path, $result); } else { eval(ltrim($result, '<?php')); } $this->triggerEvent('on_class_built', [$base_manager_class_name, $base_class_build_path]); }
/** * Prepare belongs to constraint statement. * * @param TypeInterface $type * @param TriggerInterface $trigger * @return string */ public function prepareCreateTriggerStatement(TypeInterface $type, TriggerInterface $trigger) { if (strpos($trigger->getBody(), "\n") === false) { return rtrim('CREATE TRIGGER ' . $this->getConnection()->escapeFieldName($trigger->getName()) . ' ' . strtoupper($trigger->getTime()) . ' ' . strtoupper($trigger->getEvent()) . ' ON ' . $this->getConnection()->escapeTableName($type->getName()) . ' FOR EACH ROW ' . $trigger->getBody(), ';') . ';'; } else { $result = []; $result[] = 'CREATE TRIGGER ' . $this->getConnection()->escapeFieldName($trigger->getName()) . ' ' . strtoupper($trigger->getTime()) . ' ' . strtoupper($trigger->getEvent()) . ' ON ' . $this->getConnection()->escapeTableName($type->getName()); $result[] = 'FOR EACH ROW BEGIN'; $result[] = $trigger->getBody(); $result[] = 'END;'; return $this->wrapDelimiter(implode("\n", $result)); } }
/** * @param TypeInterface $type */ public function buildType(TypeInterface $type) { $class_name = Inflector::classify(Inflector::singularize($type->getName())); $base_class_name = 'Base\\' . $class_name; $class_build_path = $this->getBuildPath() ? "{$this->getBuildPath()}/{$class_name}.php" : null; if ($class_build_path && is_file($class_build_path)) { $this->triggerEvent('on_class_build_skipped', [$class_name, $class_build_path]); return; } $result = []; $result[] = '<?php'; $result[] = ''; if ($this->getStructure()->getConfig('header_comment')) { $result = array_merge($result, explode("\n", $this->getStructure()->getConfig('header_comment'))); $result[] = ''; } if ($this->getStructure()->getNamespace()) { $result[] = 'namespace ' . $this->getStructure()->getNamespace() . ';'; $result[] = ''; $result[] = '/**'; $result[] = ' * @package ' . $this->getStructure()->getNamespace(); $result[] = ' */'; } $result[] = 'class ' . $class_name . ' extends ' . $base_class_name; $result[] = '{'; $result[] = '}'; $result[] = ''; $result = implode("\n", $result); if ($this->getBuildPath()) { file_put_contents($class_build_path, $result); } else { eval(ltrim($result, '<?php')); } $this->triggerEvent('on_class_built', [$class_name, $class_build_path]); }
/** * @param TypeInterface $type */ public function buildType(TypeInterface $type) { $base_class_name = Inflector::classify(Inflector::singularize($type->getName())); $base_class_extends = '\\' . ltrim($type->getBaseClassExtends(), '\\'); $base_class_build_path = $this->getBuildPath() ? "{$this->getBuildPath()}/Base/{$base_class_name}.php" : null; $result = []; $result[] = '<?php'; $result[] = ''; if ($this->getStructure()->getConfig('header_comment')) { $result = array_merge($result, explode("\n", $this->getStructure()->getConfig('header_comment'))); $result[] = ''; } $base_class_namespace = $this->getStructure()->getNamespace() ? $this->getStructure()->getNamespace() . '\\Base' : 'Base'; $result[] = 'namespace ' . $base_class_namespace . ';'; $result[] = ''; $result[] = '/**'; $this->buildBaseClassDocBlockProperties('', $result); $result[] = ' * @package ' . $base_class_namespace; $result[] = ' */'; $interfaces = $traits = []; foreach ($type->getTraits() as $interface => $implementations) { if ($interface != '--just-paste-trait--') { $interfaces[] = '\\' . ltrim($interface, '\\'); } if (count($implementations)) { foreach ($implementations as $implementation) { $traits[] = '\\' . ltrim($implementation, '\\'); } } } $result[] = 'abstract class ' . $base_class_name . ' extends ' . $base_class_extends . (empty($interfaces) ? '' : ' implements ' . implode(', ', $interfaces)); $result[] = '{'; if (count($traits)) { $trait_tweaks_count = count($type->getTraitTweaks()); $result[] = ' use ' . implode(', ', $traits) . ($trait_tweaks_count ? '{' : ';'); if ($trait_tweaks_count) { for ($i = 0; $i < $trait_tweaks_count - 1; ++$i) { $result[] = ' ' . $type->getTraitTweaks()[$i] . ($i < $trait_tweaks_count - 2 ? ',' : ''); } $result[] = ' }'; } $result[] = ''; } $result[] = ' /**'; $result[] = ' * Name of the table where records are stored.'; $result[] = ' *'; $result[] = ' * @var string'; $result[] = ' */'; $result[] = ' protected $table_name = ' . var_export($type->getTableName(), true) . ';'; $fields = $type->getAllFields(); $this->buildFields($fields, ' ', $result); $this->buildGeneratedFields(array_keys($type->getGeneratedFields()), ' ', $result); if (count($type->getProtectedFields())) { $result[] = ''; $result[] = ' /**'; $result[] = ' * List of protected fields.'; $result[] = ' *'; $result[] = ' * @var array'; $result[] = ' */'; $result[] = ' protected $protected_fields = [' . implode(', ', array_map(function ($field) { return var_export($field, true); }, $type->getProtectedFields())) . '];'; } if ($type->getOrderBy() != ['id']) { $result[] = ''; $result[] = ' /**'; $result[] = ' * @var string[]'; $result[] = ' */'; $result[] = ' protected $order_by = [' . implode(', ', array_map(function ($value) { return var_export($value, true); }, $type->getOrderBy())) . '];'; } $this->buildConfigureMethod($type->getGeneratedFields(), ' ', $result); foreach ($type->getAssociations() as $association) { $association->buildClassMethods($this->getStructure(), $type, $this->getStructure()->getType($association->getTargetTypeName()), $result); } foreach ($fields as $field) { if ($field instanceof ScalarField && $field->getShouldBeAddedToModel() && $field->getName() != 'id') { $this->buildFieldGetterAndSetter($field, ' ', $result); } } foreach ($type->getGeneratedFields() as $field_name => $caster) { $this->buildGeneratedFieldGetter($field_name, $caster, ' ', $result); } $build_custom_get_field_value = false; foreach ($fields as $field) { if ($field instanceof ScalarField && $field->getShouldBeAddedToModel() && !empty($field->getDeserializingCode('raw_value'))) { $build_custom_get_field_value = true; break; } } if ($build_custom_get_field_value) { $result[] = ''; $result[] = ' /**'; $result[] = ' * {@inheritdoc}'; $result[] = ' */'; $result[] = ' public function getFieldValue($field, $default = null)'; $result[] = ' {'; $result[] = ' $value = parent::getFieldValue($field, $default);'; $result[] = ''; $result[] = ' if ($value === null) {'; $result[] = ' return null;'; $result[] = ' } else {'; $result[] = ' switch ($field) {'; foreach ($fields as $field) { if ($field instanceof ScalarField && $field->getShouldBeAddedToModel() && !empty($field->getDeserializingCode('value'))) { $result[] = ' case ' . var_export($field->getName(), true) . ':'; $result[] = ' return ' . $field->getDeserializingCode('value') . ';'; } } $result[] = ' }'; $result[] = ''; $result[] = ' return $value;'; $result[] = ' }'; $result[] = ' }'; } $result[] = ''; $result[] = ' /**'; $result[] = ' * {@inheritdoc}'; $result[] = ' */'; $result[] = ' public function &setFieldValue($name, $value)'; $result[] = ' {'; $result[] = ' if ($value === null) {'; $result[] = ' parent::setFieldValue($name, null);'; $result[] = ' } else {'; $result[] = ' switch ($name) {'; $casters = []; foreach ($fields as $field) { if ($field instanceof ScalarField && $field->getShouldBeAddedToModel()) { $casting_code = $field->getCastingCode('value'); if (empty($casters[$casting_code])) { $casters[$casting_code] = []; } $casters[$casting_code][] = $field->getName(); } } foreach ($casters as $caster_code => $casted_field_names) { foreach ($casted_field_names as $casted_field_name) { $result[] = ' case ' . var_export($casted_field_name, true) . ':'; } $result[] = ' return parent::setFieldValue($name, ' . $caster_code . ');'; } $result[] = ' default:'; $result[] = ' if ($this->isLoading()) {'; $result[] = ' return parent::setFieldValue($name, $value);'; $result[] = ' } else {'; $result[] = ' if ($this->isGeneratedField($name)) {'; $result[] = ' throw new \\LogicException("Generated field $name cannot be set by directly assigning a value");'; $result[] = ' } else {'; $result[] = ' throw new \\InvalidArgumentException("Field $name does not exist in this table");'; $result[] = ' }'; $result[] = ' }'; $result[] = ' }'; $result[] = ' }'; $result[] = ''; $result[] = ' return $this;'; $result[] = ' }'; $this->buildJsonSerialize($type->getSerialize(), ' ', $result); $this->buildCompositeFieldMethods($type->getFields(), ' ', $result); $this->buildValidate($type->getFields(), $type->getAssociations(), ' ', $result); $result[] = '}'; $result[] = ''; $result = implode("\n", $result); if ($this->getBuildPath()) { file_put_contents($base_class_build_path, $result); } else { eval(ltrim($result, '<?php')); } $this->triggerEvent('on_class_built', [$base_class_name, $base_class_build_path]); }
/** * Build class methods. * * @param StructureInterface $structure * @param TypeInterface $source_type * @param TypeInterface $target_type * @param array $result */ public function buildClassMethods(StructureInterface $structure, TypeInterface $source_type, TypeInterface $target_type, array &$result) { $namespace = $structure->getNamespace(); if ($namespace) { $namespace = '\\' . ltrim($namespace, '\\'); } $target_instance_class = $namespace . '\\' . Inflector::classify(Inflector::singularize($target_type->getName())); $classified_association_name = Inflector::classify($this->getName()); $getter_name = "get{$classified_association_name}"; $setter_name = "set{$classified_association_name}"; $fk_getter_name = "get{$classified_association_name}Id"; $fk_setter_name = "set{$classified_association_name}Id"; $result[] = ''; $result[] = ' /**'; $result[] = ' * Return ' . Inflector::singularize($source_type->getName()) . ' ' . $this->getName() . '.'; $result[] = ' *'; $result[] = ' * @return ' . $target_instance_class; $result[] = ' */'; $result[] = ' public function ' . $getter_name . '()'; $result[] = ' {'; $result[] = ' return $this->pool->getById(' . var_export($target_instance_class, true) . ', $this->' . $fk_getter_name . '());'; $result[] = ' }'; $setter_access_level = $this->getProtectSetter() ? 'protected' : 'public'; $result[] = ''; $result[] = ' /**'; $result[] = ' * Set ' . Inflector::singularize($source_type->getName()) . ' ' . $this->getName() . '.'; $result[] = ' *'; $result[] = ' * @param ' . $target_instance_class . ' $value'; $result[] = ' * @return $this'; $result[] = ' */'; $result[] = ' ' . $setter_access_level . ' function &' . $setter_name . '(' . $target_instance_class . ' $value' . ($this->isRequired() ? '' : ' = null') . ')'; $result[] = ' {'; if ($this->isRequired()) { $result[] = ' if (empty($value) || !$value->isLoaded()) {'; $result[] = ' throw new \\InvalidArgumentException(\'Valid related instance is required\');'; $result[] = ' }'; $result[] = ''; $result[] = ' $this->' . $fk_setter_name . '($value->getId());'; $result[] = ''; $result[] = ' return $this;'; } else { $result[] = ' if (empty($value)) {'; $result[] = ' $this->' . $fk_setter_name . '(0);'; $result[] = ' } else {'; $result[] = ' $this->' . $fk_setter_name . '($value->getId());'; $result[] = ' }'; $result[] = ''; $result[] = ' return $this;'; } $result[] = ' }'; }
/** * Return full instance class from namespace and type. * * @param string $namespace * @param TypeInterface $type * @return string */ protected function getInstanceClassFrom($namespace, TypeInterface $type) { return $namespace . '\\' . Inflector::classify(Inflector::singularize($type->getName())); }
/** * Prepare has one constraint statement. * * @param TypeInterface $type * @param HasOneAssociation $association * @return string */ public function prepareHasOneConstraintStatement(TypeInterface $type, HasOneAssociation $association) { $result = []; $result[] = 'ALTER TABLE ' . $this->getConnection()->escapeTableName($type->getName()); $result[] = ' ADD CONSTRAINT ' . $this->getConnection()->escapeFieldName($association->getConstraintName()); $result[] = ' FOREIGN KEY (' . $this->getConnection()->escapeFieldName($association->getFieldName()) . ') REFERENCES ' . $this->getConnection()->escapeTableName($association->getTargetTypeName()) . '(`id`)'; if ($association->isRequired()) { $result[] = ' ON UPDATE CASCADE ON DELETE CASCADE;'; } else { $result[] = ' ON UPDATE SET NULL ON DELETE SET NULL;'; } return implode("\n", $result); }
/** * {@inheritdoc} */ public function buildClearRelatedObjectsMethod(StructureInterface $structure, TypeInterface $source_type, TypeInterface $target_type, $namespace, array &$result) { $intermediary_type = $structure->getType($this->intermediary_type_name); $intermediary_instance_class = $this->getInstanceClassFrom($namespace, $intermediary_type); $result[] = ''; $result[] = ' /**'; $result[] = ' * Drop all connections between ' . str_replace('_', ' ', $target_type->getName()) . ' and this ' . Inflector::singularize($source_type->getName()) . '.'; $result[] = ' *'; $result[] = ' * @return $this'; $result[] = ' */'; $result[] = " public function &clear{$this->getClassifiedAssociationName()}()"; $result[] = ' {'; $result[] = ' if ($objects = $this->get' . $this->getClassifiedAssociationName() . '()) {'; $result[] = ' $object_ids = [];'; $result[] = ''; $result[] = ' $this->connection->transact(function () use ($objects, &$object_ids) {'; $result[] = ' foreach ($objects as $object) {'; $result[] = ' $object_ids[] = $object->getId();'; $result[] = ' $object->delete(true);'; $result[] = ' }'; $result[] = ' });'; $result[] = ''; $result[] = ' $this->pool->forget(' . var_export($intermediary_instance_class, true) . ', $object_ids);'; $result[] = ' }'; $result[] = ''; $result[] = ' return $this;'; $result[] = ' }'; }
/** * Return name of the connection that will be created for has and belongs to many association. * * @param TypeInterface $source * @param TypeInterface $target * @return string */ private function getConnectionTableName(TypeInterface $source, TypeInterface $target) { return $source->getName() . '_' . $target->getName(); }