protected function generateModelClassMethods($modelName) { $methods = array(); foreach ($this->modelsConfig->models[$modelName]->properties as $propName => $propConfig) { $name = ucfirst($propName); $this->lastProcessedElement = $modelName . '.' . $propName; if ($propName == 'id') { continue; } $type = $this->typeConverter->getPhpType($propConfig->type); $setterType = $this->typeConverter->getSetterPhpdocType($propConfig->type); $methods['force']['get' . $name] = $this->unindent(3, "\n /**\n * Do not override! Grace internals rely on these methods only containing the array access.\n * @return {$type}\n */\n public function get{$name}()\n {\n return \$this->properties['{$propName}'];\n }\n "); // TODO берём из конфига валидацию и по ней накидываем тут преобразования а-ля Phone::normalizePhone() // можно однако напороться на переопределённый сеттер, который это не делает if ($propConfig->isSettable) { $methods['optional']['set' . $name] = $this->unindent(4, "\n /**\n * @param {$setterType} \${$propName}\n * @return \$this\n */\n public function set{$name}(\${$propName})\n {\n return \$this->setProperty('{$propName}', \${$propName});\n }\n "); } if ($propConfig->resolvesToModelName) { $getterName = 'get' . ucfirst(substr($propName, 0, -2)); // removing Id suffix: regionId => getRegion $foreignClass = $this->classNameProvider->getModelClass($propConfig->resolvesToModelName); $finderProperty = lcfirst($propConfig->resolvesToModelName) . 'Finder'; $methods['force'][$getterName] = $this->unindent(4, "\n /**\n * Do not override\n * @return {$foreignClass}\n */\n public function {$getterName}()\n {\n return \$this->orm->{$finderProperty}->getByIdOrFalse(\$this->getProperty('{$propName}'));\n }\n "); } } // DB TO PHP CONVERSION $dbToPhpMethodBody = ''; foreach ($this->modelsConfig->models[$modelName]->properties as $propName => $propConfig) { $this->lastProcessedElement = $modelName . '.' . $propName; $propertyCode = $this->typeConverter->getDbToPhpConverterCode($propConfig->type); if ($propConfig->isNullable) { $dbToPhpMethodBody .= $this->unindent(1, "\n // {$propName}\n \$value = \$dbArray['{$propName}'];\n \$this->properties['{$propName}'] = (\$value === null) ? null : ({$propertyCode});\n "); } else { $dbToPhpMethodBody .= $this->unindent(1, "\n // {$propName}\n \$value = \$dbArray['{$propName}'];\n if (\$value === null) {\n throw new \\Grace\\ORM\\Type\\ConversionImpossibleException('Null is not allowed in {$modelName}.{$propName}');\n }\n \$this->properties['{$propName}'] = {$propertyCode};\n "); } } $methods['force']['setPropertiesFromDbArray'] = $this->unindent(2, "\n /** Do not override */\n protected function setPropertiesFromDbArray(array \$dbArray)\n {\n {$dbToPhpMethodBody}\n }\n "); // INITIAL PROPERTY VALUES $initPropsMethodBody = ''; foreach ($this->modelsConfig->models[$modelName]->properties as $propName => $propConfig) { $type = $propConfig->type; if ($propConfig->default) { $valueDef = $propConfig->default; $rawValueCode = $valueDef === 'now' ? '\\Grace\\ORM\\Type\\TypeTimestamp::format(time())' : var_export($valueDef, true); $isNullAllowed = $propConfig->isNullable; // TODO убрать необходимость в этом вызове $valueCode = '$this->orm->typeConverter->convertOnSetter(' . var_export($type, true) . ', ' . $rawValueCode . ', ' . var_export($isNullAllowed, true) . ')'; } else { if ($propConfig->isNullable) { $valueCode = 'null'; } else { $valueCode = $this->typeConverter->getPhpDefaultValueCode($type); } } $initPropsMethodBody .= "\n '{$propName}' => {$valueCode},"; } $initPropsMethodBody .= "\n "; $methods['force']['setDefaultPropertyValues'] = $this->unindent(2, "\n /** Do not override */\n protected function setDefaultPropertyValues()\n {\n \$this->properties = array({$initPropsMethodBody});\n }\n "); return $methods; }
private static function parseMapping($mapping, $modelName, $propertyName, TypeConverter $typeConverter) { $me = new MappingElement(); if (preg_match('/^(\\w+):(\\w+)$/', $mapping, $match)) { // две строки через двоеточие — relationProp:foreignProp, прокси-поле $me->relationLocalProperty = $match[1]; $me->relationForeignProperty = $match[2]; } elseif (strtoupper($mapping[0]) == $mapping[0]) { // начинается с прописной буквы — модель, т.е. внешний ключ $me->foreignKeyTable = $mapping; } elseif ($mapping) { // не начинается с прописной буквы — тип данных, локальное поле if (!$typeConverter->hasType($mapping)) { throw new ConfigLoadException("Incorrect type \"{$mapping}\" for {$modelName}.{$propertyName}"); } $me->localPropertyType = $mapping; } else { throw new ConfigLoadException("Cannot parse mapping \"{$mapping}\" for {$modelName}.{$propertyName}"); } return $me; }
private function getFieldsSQL(ConnectionInterface $db, TypeConverter $typeConverter, ModelElement $config) { $sql = array(); foreach ($config->properties as $propName => $propConfig) { if (!$propConfig->isLocalInDb) { continue; } $type = $typeConverter->getDbType($propConfig->type); $nullSql = $propConfig->isNullable ? '' : 'NOT NULL'; $sql[] = $db->replacePlaceholders("?f ?p {$nullSql}", array($propName, $type)); } return implode(",\n", $sql); }