<?php require_once getenv('PHOCOA_PROJECT_CONF'); if ($argc != 2) { die("Usage: scaffold.php 'entity1 entity2 ...'\n"); } $adapter = 'Propel'; if (defined('ORM_MODEL_ADAPTER')) { $adapter = ORM_MODEL_ADAPTER; } $builder = 'WFModelCodeGenPropel'; $configFile = APP_ROOT . '/propel-build/phocoa-generator-config.yaml'; if (!file_exists($configFile)) { $configFile = NULL; } $delim = ' '; if (strchr($argv[1], ',')) { $delim = ','; } $entities = array_map("trim", explode($delim, $argv[1])); $model = WFModel::sharedModel(); $model->buildModel($adapter, $configFile, $entities); foreach ($model->entities() as $entity) { $codeGen = new $builder(); try { $codeGen->generateModuleForEntity($entity); } catch (Exception $e) { print "Error generating scaffold for entity '{$entity}': " . $e->getMessage() . "\n"; } }
/** * Create an object of Class with the passed name/value pairs. * * @param string The class of object to create. * @return object The instance created. * @throws object WFException */ protected function makeObj($class, $props) { if (!is_array($props)) { throw new WFException("Class definition for {$class} doesn't have any properties. Properties must be defined in an array."); } $model = WFModel::sharedModel(); $o = new $class(); if ($o instanceof BaseObject) { // model object; could have relationships, see if we need to build it... if (!$model->getEntity($class)) { $model->buildModel($this->getOpt(self::OPT_MODEL_ADAPTER), NULL, array($class)); } foreach ($props as $k => $v) { // is this an attribute or a relationship? $entity = $model->getEntity($class); if ($entity->getProperty($k)) { // it's a basic property if (!is_array($v)) { // is $v a php eval? $matches = array(); if (preg_match('/<\\?php (.*)\\?' . '>/', $v, $matches)) { $v = eval("return {$matches[1]};"); } $o->setValueForKey($v, $k); } else { // "value" for this key is an object. if (count(array_keys($v)) != 1) { throw new WFException("Fixtures can pass only scalars or objects. Arrays of object are not supported."); } $subClass = key($v); $subClassProps = $v[$subClass]; $subObj = $this->makeObj($subClass, $subClassProps); $o->setValueForKey($subObj, $k); } } else { // not a property, it is a relationship... // see if we can get that relationship if (!$model->getEntity($k)) { // try to build the entity; can't get all relationships unless we build the related entity try { $model->buildModel($this->getOpt(self::OPT_MODEL_ADAPTER), NULL, array($k)); } catch (Exception $e) { // maybe it's an instance variable or just a KVC property? try { // is $v a php eval? $matches = array(); if (preg_match('/<\\?php (.*)\\?' . '>/', $v, $matches)) { $v = eval("return {$matches[1]};"); } $o->setValueForKey($v, $k); continue; } catch (Exception $e) { throw new WFException("{$k} is not a known Propel entity, nor is it a KVC method:" . $e->getMessage()); } } } $rel = $entity->getRelationship($k); if (!$rel) { // maybe it's an instance variable or just a KVC property? try { // is $v a php eval? $matches = array(); if (preg_match('/<\\?php (.*)\\?' . '>/', $v, $matches)) { $v = eval("return {$matches[1]};"); } $o->setValueForKey($v, $k); continue; } catch (Exception $e) { throw new WFException("{$k} is not a manifested entity relationship or a KVC-compliant property of {$class}."); } } if ($rel->valueForKey('toOne')) { // check for "empty" object if ($v === NULL) { $v = array(); } if (is_array($v)) { // treat the obj as an "inline object" $subObj = $this->makeObj($k, $v); } else { // we expect an object here. this could be either a named object or result of an eval // is $v a php eval? $matches = array(); if (preg_match('/<\\?php (.*)\\?>/', $v, $matches)) { $subObj = eval("return {$matches[1]};"); if (!is_object($subObj)) { throw new WFException("Result of eval for relationship {$v} is not an object: " . $matches[1]); } } else { if (!isset($this->objById[$k][$v])) { throw new WFException("No {$k} with label {$v}."); } $subObj = $this->objById[$k][$v]; } } $o->setValueForKey($subObj, $k); } else { foreach ($v as $index => $subClassProps) { try { // we expect an object here. this could be either a named object or result of an "inline" object via YAML // if subClassProps is a string, it's the former. if (is_string($subClassProps)) { if (!isset($this->objById[$k][$subClassProps])) { throw new WFException("Failed to find a named object of class {$k} with label {$subClassProps}."); } $subObj = $this->objById[$k][$subClassProps]; } else { $subObj = $this->makeObj($k, $v[$index]); } } catch (Exception $e) { throw new WFException("Error processing {$index} class={$k}: " . $e->getMessage()); } $toManyAdderF = "add" . $k; $o->{$toManyAdderF}($subObj); if (gettype($index) != 'integer') { if (isset($this->objById[$k][$index])) { throw new Exception("There already exists a {$k} for id {$index}."); } $this->objById[$k][$index] = $subObj; } } } } } } else { // simple object; has to contain key-value pairs. foreach ($props as $k => $v) { $o->setValueForKey($v, $k); } } return $o; }
/** * Pass in a WFModelEntity object with a name filled out. * * @param object WFModelEntity An WFModelEntity with a name. * @throws object WFModelEntity */ function buildEntityModel($entity) { if (!$entity instanceof WFModelEntity) { throw new WFException("WFModelEntity required."); } $name = $entity->valueForKey('name'); if (isset($this->builtEntities[$name])) { return $this->builtEntities[$name]; } // build a WFModelEntity structure from the Propel metadata.... $tableMap = $this->getEntityMetadata($name); // set up properties foreach ($tableMap->getColumns() as $column) { $property = new WFModelEntityProperty(); $propertyName = $column->getPhpName(); $propertyName[0] = strtolower($propertyName[0]); $property->setValueForKey($propertyName, 'name'); $property->setValueForKey($column->getDefaultValue(), 'defaultValue'); // BOOLEAN|TINYINT|SMALLINT|INTEGER|BIGINT|DOUBLE|FLOAT|REAL|DECIMAL|CHAR|{VARCHAR}|LONGVARCHAR|DATE|TIME|TIMESTAMP|BLOB|CLOB switch (strtoupper($column->getType())) { case 'TINYINT': case 'SMALLINT': case 'INTEGER': case 'BIGINT': case 'DOUBLE': case 'NUMERIC': case 'FLOAT': case 'REAL': case 'DECIMAL': $type = WFModelEntityProperty::TYPE_NUMBER; break; case 'TIMESTAMP': case 'DATETIME': case 'DATE': $type = WFModelEntityProperty::TYPE_DATETIME; break; case 'TEXT': case 'LONGVARCHAR': $type = WFModelEntityProperty::TYPE_TEXT; break; case 'BOOLEAN': $type = WFModelEntityProperty::TYPE_BOOLEAN; break; case 'CHAR': case 'VARCHAR': case 'STRING': $type = WFModelEntityProperty::TYPE_STRING; break; default: print "WARNING: Unknown property type for column " . $property->valueForKey('name') . ": " . $column->getType() . "\n"; $type = WFModelEntityProperty::TYPE_STRING; break; } if (!$entity->valueForKey('descriptiveColumnName') && $type === WFModelEntityProperty::TYPE_STRING) { $entity->setValueForKey($property->valueForKey('name'), 'descriptiveColumnName'); } if (!$entity->valueForKey('primaryKeyProperty') && $column->isPrimaryKey()) { $entity->setValueForKey($property->valueForKey('name'), 'primaryKeyProperty'); } $property->setValueForKey($type, 'type'); $entity->addProperty($property); } if (!$entity->valueForKey('descriptiveColumnName')) { $entity->setValueForKey($entity->valueForKey('primaryKeyProperty'), 'descriptiveColumnName'); } // set up relationships $tableMap->getRelations(); // populate databaseMap with related columns foreach ($tableMap->getColumns() as $column) { if (!$column->isForeignKey()) { continue; } //print "Processing {$tableMap->getPhpName()}.{$column->getPhpName()}\n"; // get related entity $relatedEntityName = $column->getRelatedTable()->getPhpName(); $relatedEntityTableMap = $this->getEntityMetadata($relatedEntityName); $relatedEntity = WFModel::sharedModel()->getEntity($relatedEntityTableMap->getPhpName()); if (!$relatedEntity) { //print "Building related WFModel entity {$relatedEntityTableMap->getPhpName()}\n"; $relatedEntity = WFModel::sharedModel()->buildEntity($relatedEntityTableMap->getPhpName()); } // configure relationship $relName = $relatedEntity->valueForKey('name'); if (!$entity->getRelationship($relName)) { // create relationship from this table to the other one $rel = new WFModelEntityRelationship(); $rel->setToOne(true); // if we are the fk column, it must be to-one (unless it's many-to-many) $rel->setValueForKey($relName, 'name'); // singular $rel->setValueForKey($column->isNotNull(), 'required'); $entity->addRelationship($rel); } // create relationship in the other direction $invRelName = $tableMap->getPhpName(); // make plural as needed - if (!$relatedEntity->getRelationship($invRelName)) { $invRel = new WFModelEntityRelationship(); // configure relationship $inverseRelationshipIsToOne = false; // is this an "extension" table? TRUE if the relationship is on our PK; this makes the INVERSE relationship have an EXT relationship to this table if ($column->isPrimaryKey()) { $inverseRelationshipIsToOne = true; $invRel->setValueForKey(true, 'isExtension'); } $invRel->setToOne($inverseRelationshipIsToOne); $invRel->setValueForKey($invRelName, 'name'); $relatedEntity->addRelationship($invRel); } } $this->builtEntities[$entity->valueForKey('name')] = $entity; }