Location: PHPKode > projects > Sierra-php PHP Application Framework > sierra/lib/model/SRA_EntityGenerator.php
<?php
// {{{ Header
/*
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
 | SIERRA : PHP Application Framework  http://code.google.com/p/sierra-php |
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
 | Copyright 2005 Jason Read                                               |
 |                                                                         |
 | Licensed under the Apache License, Version 2.0 (the "License");         |
 | you may not use this file except in compliance with the License.        |
 | You may obtain a copy of the License at                                 |
 |                                                                         |
 |     http://www.apache.org/licenses/LICENSE-2.0                          |
 |                                                                         |
 | Unless required by applicable law or agreed to in writing, software     |
 | distributed under the License is distributed on an "AS IS" BASIS,       |
 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.|
 | See the License for the specific language governing permissions and     |
 | limitations under the License.                                          |
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
 */
// }}}

// {{{ Imports
require_once('model/SRA_Generator.php');
require_once('model/SRA_AttributeGenerator.php');
require_once('model/SRA_ValidateGenerator.php');
require_once('model/SRA_FileAttribute.php');
require_once('model/SRA_EntitySchema.php');
require_once('model/SRA_EntityView.php');
require_once('model/SRA_EntityViewProcessor.php');
require_once('model/SRA_AopAspect.php');
require_once('model/SRA_AopIntroduction.php');
require_once('model/SRA_WS.php');
// }}}

// {{{ Constants

/**
 * the class suffix to use for DAOs
 */
define('SRA_ENTITY_GENERATOR_DAO_SUFFIX', 'DAO');

/**
 * the class suffix to use for VOs
 */
define('SRA_ENTITY_GENERATOR_VO_SUFFIX', 'VO');

/**
 * the max # of recursive hits that are allows to the getSchema method. if this 
 * # is exceeded, an SRA_Error will be logged and the process will be killed using 
 * the exit function
 */
define('SRA_ENTITY_GENERATOR_MAX_SCHEMA_RECURSION', 20);

// }}}

// {{{ SRA_EntityGenerator
/**
 * Used to generate an entity model entity
 * 
 * @author  Jason Read <hide@address.com>
 * @package sierra.model
 */
class SRA_EntityGenerator extends SRA_Generator {
  // {{{ Attributes
  // public attributes
  
  // private attributes
	var $_name;
  var $_aopAspects = array();
  var $_aopIntroductions = array();
	var $_abstract;
	var $_apiResource;
  var $_attributeGenerators = array();
	var $_columnPostfix = '';
	var $_columnPrefix = '';
	var $_constraint;
  var $_customDao;
	var $_dao;
	var $_daoFile;
	var $_daoExtends;
	var $_daoExtendsFile;
	var $_daoSuffix;
	var $_db;
	var $_dbRefIntegrity;
	var $_ddlCamelCase;
	var $_ddlUpperCase;
  var $_defaultViews;
  var $_dtdAttributes;
	var $_dtdCamelCase;
  var $_dtdSubElements;
	var $_entityGenerators;
	var $_entityModelXml;
	var $_fileDir;
	var $_fileDirUri;
	var $_fileHandling;
  var $_fileIconDir;
	var $_fileScriptRewrite;
	var $_fileScriptUri;
	var $_generatePath;
	var $_globalViews;
  var $_ignoreBadImport;
  var $_matchUserId;
	var $_msgs;
	var $_nestedQueriesOk;
	var $_nullDbEmptyStr;
  var $_onCreateImport;
	var $_onDeleteUpdate;
	var $_orderBy;
	var $_parentEntity;
	var $_primaryKey;
	var $_propagateUpdate;
  var $_renderAppend;
  var $_renderExclude;
  var $_renderInclude;
	var $_resource;
  var $_resourceBundles = FALSE;
	var $_resources;
	var $_resourceHelp;
	var $_schema;
	var $_schemaLoading = FALSE;
	var $_schemaRecursionCount = 0;
	var $_skipPersistence;
  var $_skipWsdl;
	var $_sysErrResource;
	var $_table;
	var $_types;
  var $_unitTest;
  var $_unitTestClass;
	var $_viewProcessors;
	var $_views;
	var $_voExtends;
	var $_voExtendsFile;
	var $_voSuffix;
	var $_validateGenerators;
  var $_webServices = array();
  var $_wsDb;
  var $_wsDbName;
	
  // }}}
  
  // {{{ Operations
  // constructor(s)
	// {{{ SRA_EntityGenerator
	/**
	 * Creates a new SRA_EntityGenerator with the configuration specified
	 * @param boolean $ddlCamelCase whether or not to generate camel case ddl
	 * @param boolean $dtdCamelCase whether or not to generate camel case dtds
	 * @param string $generatePath the directory where generated class should be 
	 * created
	 * @param array $types an array of all of the entity types defined in the 
	 * entity model xml configuration
	 * @param string $entityModelXml path to the entity model xml configuration
	 * @param string $sysErrResource the system error resource key
	 * @param array $conf associative array of entity configuration values
	 * @param ViewProcessor[] $viewProcessors global view processors that may be 
	 * used by this entity
	 * @param SRA_EntityView[] $globalViews global views that this entity or its attributes' views may extend from
   * @access  private
	 */
	function SRA_EntityGenerator($dbKey, $dbRefIntegrity, $ddlCamelCase, $ddlUpperCase, $dtdCamelCase, $msgs, $nestedQueriesOk, $generatePath, $types, $entityModelXml, $resources, $sysErrResource, & $conf, & $viewProcessors, & $globalViews, $defaultViews, $daoSuffix, $voSuffix, $wsDb) {
		
		$this->_name = $conf['attributes']['key'];
		$this->_abstract = isset($conf['attributes']['abstract']) && $conf['attributes']['abstract'] == '1';
		$this->_entityModelXml = $entityModelXml;
		$this->_viewProcessors =& $viewProcessors;
		$this->_globalViews =& $globalViews;
    $this->_defaultViews = $defaultViews;
    // default views
    if (isset($conf['default-view']) && SRA_Error::isError($entityDefaultViews = SRA_Generator::getDefaultViews($conf['default-view'], $globalViews))) {
      return $entityDefaultViews;
    }
    if ($entityDefaultViews) { $this->_defaultViews = array_merge($entityDefaultViews, $this->_defaultViews ? $this->_defaultViews : array()); }
		
		if (isset($conf['attributes']['resources']) && $conf['attributes']['resources']) {
			$this->_resources = $conf['attributes']['resources'];
		}
		else {
			$this->_resources = $resources;
		}
		if ($this->_resources && !is_array($this->_resources)) {
			$this->_resources = explode(' ', $this->_resources);
		}
		if (isset($conf['attributes']['ws-db']) && $conf['attributes']['ws-db']) {
			$this->_wsDb = $conf['attributes']['ws-db'];
		}
		else {
			$this->_wsDb = $wsDb;
		}
    $this->_wsDbName = isset($conf['attributes']['ws-db-name']) ? $conf['attributes']['ws-db-name'] : NULL;
		
		$this->_ddlCamelCase = $ddlCamelCase;
		$this->_ddlUpperCase = $ddlUpperCase;
		$this->_dtdCamelCase = $dtdCamelCase;
		$this->_fileHandling = $conf['attributes']['file-handling'];
    $this->_matchUserId = $conf['attributes']['match-user-id'];
		$this->_nullDbEmptyStr = isset($conf['attributes']['null-db-empty-str']) && $conf['attributes']['null-db-empty-str'] == '1';
    $this->_skipPersistence = isset($conf['attributes']['skip-persistence']) && $conf['attributes']['skip-persistence'] == '1';
		
		// validate configuration
		
		// missing mandatory attributes
		if (!count($conf['attribute']) || !$conf['attributes']['key']) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Missing 'attribute' 'key' for entity " . $conf['attributes']['key'];
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
		
		$this->_resource = $this->getResource($conf, $this->_resources, array('entity', 'text'));
		$this->_resourceHelp = $this->getHelpResource($conf, $this->_resources, array('entity'));

		// validate api-resource
		if ($conf['attributes']['api-resource'] && !SRA_Generator::validateResource($conf['attributes']['api-resource'], $this->_resources)) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - api-resource '" . $conf['attributes']['api-resource'] . "' is not valid for entity " . $conf['attributes']['key'];
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
		$this->_sysErrResource = $sysErrResource;
		
		// invalid dao
		if (isset($conf['attributes']['dao']) && !($daoFile = SRA_File::getRelativePath('lib', $conf['attributes']['dao'] . '.' . SRA_SYS_PHP_EXTENSION))) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed -  dao '" . $conf['attributes']['dao'] . "' class file does not exist";
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
		}
		$conf['attributes']['dao'] = isset($daoFile) && $daoFile ? basename($conf['attributes']['dao'], '.' . SRA_SYS_PHP_EXTENSION) : NULL;
		
		// invalid daoExtends
		if (isset($conf['attributes']['dao-extends']) && !($daoExtendsFile = SRA_File::getRelativePath('lib', $conf['attributes']['dao-extends'] . '.' . SRA_SYS_PHP_EXTENSION))) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed -  dao-extends '" . $conf['attributes']['dao-extends'] . "' class file does not exist";
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
		}
		$conf['attributes']['dao-extends'] = isset($daoExtendsFile) && $daoExtendsFile ? basename($conf['attributes']['dao-extends'], '.' . SRA_SYS_PHP_EXTENSION) : NULL;
    
		// invalid unit test
    if ($conf['attributes']['unit-test'] && !SRA_Util::endsWith($conf['attributes']['unit-test'], '.' . SRA_SYS_PHP_EXTENSION)) { $conf['attributes']['unit-test'] .= '.' . SRA_SYS_PHP_EXTENSION; }
		if (isset($conf['attributes']['unit-test']) && !($this->_unitTest = SRA_File::getRelativePath('lib', $conf['attributes']['unit-test']))) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed -  unit-test '" . $conf['attributes']['unit-test'] . "' class file does not exist";
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
		}
    else if ($this->_unitTest) {
      $this->_unitTestClass = str_replace('.' . SRA_SYS_PHP_EXTENSION, '', basename($this->_unitTest));
    }
		
		// invalid voExtends
		if (isset($conf['attributes']['vo-extends']) && !($voExtendsFile = SRA_File::getRelativePath('lib', $conf['attributes']['vo-extends'] . '.' . SRA_SYS_PHP_EXTENSION))) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed -  vo-extends '" . $conf['attributes']['vo-extends'] . "' class file does not exist";
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
		}
		$conf['attributes']['vo-extends'] = isset($voExtendsFile) && $voExtendsFile ? basename($conf['attributes']['vo-extends'], '.' . SRA_SYS_PHP_EXTENSION) : NULL;
		
		// validate msg
		$this->_msgs = array();
		if (isset($conf['msg'])) {
			$keys = array_keys($conf['msg']);
			foreach ($keys as $key) {
				$this->_msgs[$key] = $conf['msg'][$key]['attributes']['resource'];
			}
		}
		
		// add enclosing entity msgs
		$this->_msgs = array_merge($msgs, $this->_msgs);
		
		// views
		if (SRA_Error::isError($views =& SRA_Generator::getViews($conf['view'], $viewProcessors))) {
			return $views;
		}
		if (is_array($views) && count($views)) {
			SRA_EntityView::mergeExtends($views, $views);
			SRA_EntityView::mergeExtends($views, $globalViews);
			SRA_EntityView::setDefaultView($views);
			$this->_views =& $views;
		}
		
		// both table and dao
    $this->_customDao = isset($conf['attributes']['dao']) && $conf['attributes']['dao'] ? TRUE : FALSE;
		$this->_table = !$this->_skipPersistence && !$this->usesWsDb() && !$this->_customDao ? $this->getDdlName(isset($conf['attributes']['table']) ? $conf['attributes']['table'] : NULL, $this->_name, $this->_ddlUpperCase) : NULL;
		
		// set suffixes
		$this->_daoSuffix = $daoSuffix;
		$this->_voSuffix = $voSuffix;
		
		$this->_columnPrefix = isset($conf['attributes']['column-prefix']) ? $conf['attributes']['column-prefix'] : '';
		$this->_columnPostfix = isset($conf['attributes']['column-postfix']) ? $conf['attributes']['column-postfix'] : '';
		
		// validate primary key
		if (!$this->_abstract && ((!isset($conf['attributes']['skip-persistence']) || $conf['attributes']['skip-persistence'] == '0') && (!isset($conf['attributes']['primary-key']) || !isset($conf['attribute'][$conf['attributes']['primary-key']])))) {
			$msg = 'SRA_EntityGenerator::SRA_EntityGenerator: Failed - Valid primary key was not specified for entity ' . $conf['attributes']['key'];
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
    
    // file icon dir
    if (isset($conf['attributes']['file-icon-dir']) && !is_dir($conf['attributes']['file-icon-dir']) && !is_dir(SRA_Controller::getAppDir() . '/' . $conf['attributes']['file-icon-dir'])) {
      $msg = 'SRA_EntityGenerator::SRA_EntityGenerator: Failed - file-icon-dir ' . $conf['attributes']['file-icon-dir'] . " is not valid for $key";
      $this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
      return;
    }
    else if (isset($conf['attributes']['file-icon-dir'])) {
      $this->_fileIconDir = $conf['attributes']['file-icon-dir'];
    }
		
		// check/initialize SRA_AttributeGenerators
		$this->_primaryKey = isset($conf['attributes']['primary-key']) ? $conf['attributes']['primary-key'] : NULL;
		if (isset($conf['validate'])) {
			$vkeys = array_keys($conf['validate']);
		}
		$primaryTableHasColumn = FALSE;
		$hasFileAttrs = FALSE;
		$keys = array_keys($conf['attribute']);
		foreach ($keys as $key) {
      if ($this->_fileIconDir && !isset($conf['attribute'][$key]['attributes']['file-icon-dir'])) { $conf['attribute'][$key]['attributes']['file-icon-dir'] = $this->_fileIconDir; }
      if (isset($conf['attributes']['is-global']) && !isset($conf['attribute'][$key]['attributes']['is-global'])) { $conf['attribute'][$key]['attributes']['is-global'] = $conf['attributes']['is-global']; }
			$this->_attributeGenerators[$key] = new SRA_AttributeGenerator($conf['attribute'][$key], $ddlCamelCase, $dtdCamelCase, $this, $types);
			if (isset($this->_attributeGenerators[$key]->err)) {
				$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Attribute ${key} produced error for entity " . $conf['attributes']['key'];
				$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
				return;
			}
			if ($this->_attributeGenerators[$key]->_isFile) {
				$hasFileAttrs = TRUE;
			}
			if (!$this->_skipPersistence && !$this->usesWsDb() && !$this->_customDao && $this->_attributeGenerators[$key]->_column && (!$this->_attributeGenerators[$key]->_table || $this->_attributeGenerators[$key]->_table == $this->_table) && !$this->_attributeGenerators[$key]->_sequence) {
				$primaryTableHasColumn = TRUE;
			}
		}
		if (!$this->_skipPersistence && !$this->usesWsDb() && !$this->_customDao && !$primaryTableHasColumn) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Entity " . $conf['attributes']['key'] . ' has no columns in it\'s primary table';
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
		
		// validate file handling
		if ($hasFileAttrs) {
			$this->_fileScriptUri = $conf['attributes']['file-script-uri'];
			$this->_fileScriptRewrite = $conf['attributes']['file-script-rewrite'] == '1';
			$this->_fileDir = $conf['attributes']['file-dir'];
			if (!is_dir(dirname($this->_fileDir))) {
				if (substr($this->_fileDir, 0, 1) != '/') {
					$this->_fileDir = '/' . $this->_fileDir;
				}
				if (is_dir(SRA_Controller::getAppDir() . $this->_fileDir)) {
					$this->_fileDir = SRA_Controller::getAppDir() . $this->_fileDir;
				}
				else {
					$this->_fileDir = SRA_DIR . $this->_fileDir;
				}
			}
			$this->_fileDirUri = $conf['attributes']['file-dir-uri'];
			// no valid file handling method specified
			if (!$this->_fileHandling || ($this->_fileHandling != SRA_FILE_ATTRIBUTE_TYPE_DB && $this->_fileHandling != SRA_FILE_ATTRIBUTE_TYPE_DIR)) {
				$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid file handling: $this->_fileHandling (required) for entity " . $conf['attributes']['key'];
				$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
				return;
			}
			// validate db file handling
			else if ($this->_fileHandling == SRA_FILE_ATTRIBUTE_TYPE_DB) {
				// script uri not specified
				if (!$this->_fileScriptUri) {
					$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid file script uri (required) for entity " . $conf['attributes']['key'];
					$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
					return;
				}
				$keys = array_keys($this->_attributeGenerators);
				foreach ($keys as $key) {
					// invalid column type (must be blob for db files)
					if ($this->_attributeGenerators[$key]->_isFile && $this->_attributeGenerators[$key]->_type != SRA_DATA_TYPE_BLOB) {
						$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid column type (blob required) for entity " . $conf['attributes']['key'] . " and attribute ${key}";
						$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
						return;
					}
				}
			}
			// validate dir file handling
			else if ($this->_fileHandling == SRA_FILE_ATTRIBUTE_TYPE_DIR) {
				// dir not specified
				if (!$this->_fileDir) {
					$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid file dir (required) for entity " . $conf['attributes']['key'];
					$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
					return;
				}
				else if (!is_writable($this->_fileDir)) {
					$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid file dir (not writable) for entity " . $conf['attributes']['key'];
					$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
					return;
				}
				// dir uri not specified
				else if (!$this->_fileDirUri) {
					$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid file dir uri (required) for entity " . $conf['attributes']['key'];
					$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
					return;
				}
				$keys = array_keys($this->_attributeGenerators);
				foreach ($keys as $key) {
					// invalid column type (must be text for dir files)
					if ($this->_attributeGenerators[$key]->_isFile && $this->_attributeGenerators[$key]->_type != SRA_DATA_TYPE_STRING) {
						$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Invalid column type (text required) for entity " . $conf['attributes']['key'] . " and attribute ${key}";
						$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
						return;
					}
				}
			}
		}
    
		// check/initialize SRA_WSs
		if (isset($conf['ws'])) {
			$keys = array_keys($conf['ws']);
			foreach ($keys as $key) {
				$this->_webServices[$key] = new SRA_WS($conf['ws'][$key], $this->_name);
				if (!SRA_WS::isValid($this->_webServices[$key])) {
					$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - web service ${key} produced error for entity " . $conf['attributes']['key'];
					$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
					return;
				}
			}
		}
		
		// check/initialize SRA_ValidateGenerators
		$this->_validateGenerators = array();
		if (isset($conf['validate'])) {
			$keys = array_keys($conf['validate']);
			foreach ($keys as $key) {
				$this->_validateGenerators[$key] = new SRA_ValidateGenerator($conf['validate'][$key]);
				if (!SRA_ValidateGenerator::isValid($this->_validateGenerators[$key])) {
					$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Validation constraint ${key} produced error for entity " . $conf['attributes']['key'];
					$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
					return;
				}
			}
		}
		
		// check for conflicing types
		if (SRA_EntityModeler::isValidType($conf['attributes']['key'])) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - an entity cannot have the same name as a database type. entity: " . $conf['attributes']['key'];
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
    
    // add aop aspects
    if (isset($conf['aop'][0])) {
      $conf['aop'] = $conf['aop'][0];
      unset($conf['aop'][0]);
    }
    if (isset($conf['aop']) && isset($conf['aop']['aspect'])) {
      $keys = array_keys($conf['aop']['aspect']);
      foreach ($keys as $key) {
        $this->_aopAspects[$key] = new SRA_AopAspect($key, $conf['aop']);
        if (isset($this->_aopAspects[$key]->err)) {
          $msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Unable to instantiate aspect $key";
          $this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
          return;
        }
      }
    }

    // add aop introductions
    if (isset($conf['aop']) && isset($conf['aop']['introduction'])) {
      $keys = array_keys($conf['aop']['introduction']);
      foreach ($keys as $key) {
        $this->_aopIntroductions[$key] = new SRA_AopIntroduction($key, $conf['aop']['introduction'][$key]);
        if (isset($this->_aopIntroductions[$key]->err)) {
          $msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Unable to instantiate introduction $key";
          $this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
          return;
        }
      }
    }
		
		$this->_apiResource = $conf['attributes']['api-resource'];
		$this->_constraint = isset($conf['attributes']['constraint']) ? $conf['attributes']['constraint'] : NULL;
		$this->_db = $dbKey;
		$this->_dbRefIntegrity = $dbRefIntegrity;
		$this->_nestedQueriesOk = $nestedQueriesOk;
		$this->_generatePath = $generatePath;
    $this->_ignoreBadImport = isset($conf['attributes']['ignore-bad-import']) && $conf['attributes']['ignore-bad-import'] == '1';
    $this->_onCreateImport = isset($conf['attributes']['on-create-import']) ? $conf['attributes']['on-create-import'] : NULL;
		$this->_onDeleteUpdate = isset($conf['attributes']['on-delete-update']) ? $conf['attributes']['on-delete-update'] : NULL;
		$this->_orderBy = isset($conf['attributes']['order-by']) ? $conf['attributes']['order-by'] : NULL;
		$this->_propagateUpdate = isset($conf['attributes']['propagate-update']) && $conf['attributes']['propagate-update'] == '1';
    $this->_renderAppend = isset($conf['attributes']['render-append']) ? explode(' ', $conf['attributes']['render-append']) : array();
    $this->_renderExclude = isset($conf['attributes']['render-exclude']) ? explode(' ', $conf['attributes']['render-exclude']) : array();
    $this->_renderInclude = isset($conf['attributes']['render-include']) ? explode(' ', $conf['attributes']['render-include']) : array();
		$this->_resource = $this->_resource ? $this->_resource : $this->_name;
    $this->_skipWsdl = isset($conf['attributes']['skip-wsdl']) && $conf['attributes']['skip-wsdl'] == '1' ? TRUE : FALSE;
		$this->_types = $types;
		
		$this->_dao = isset($conf['attributes']['dao']) ? $conf['attributes']['dao'] : NULL;
		$this->_daoFile = isset($daoFile) ? $daoFile : NULL;
		$this->_daoExtends = isset($conf['attributes']['dao-extends']) ? $conf['attributes']['dao-extends'] : NULL;
		$this->_daoExtendsFile = isset($daoExtendsFile) ? $daoExtendsFile : NULL;
		$this->_voExtends = isset($conf['attributes']['vo-extends']) ? $conf['attributes']['vo-extends'] : NULL;
		$this->_voExtendsFile = isset($voExtendsFile) ? $voExtendsFile : NULL;
		
		// check for conflicting VO or DAO class names
		if ($this->_name . $this->_daoSuffix == $this->_daoExtends) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Generated DAO cannot have the same name as the extended DAO. entity: " . $conf['attributes']['key'];
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
		if ($this->_name . $this->_voSuffix == $this->_voExtends) {
			$msg = "SRA_EntityGenerator::SRA_EntityGenerator: Failed - Generated DAO cannot have the same name as the extended VO. entity: " . $conf['attributes']['key'];
			$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
			return;
		}
    
    // check for attributes not allowed with ws-db
    if ($this->usesWsDb()) {
      $err = NULL;
      if ($this->_columnPostfix) $err = 'column-postfix';
      else if ($this->_columnPrefix) $err = 'column-prefix';
      else if ($this->_constraint) $err = 'constraint';
      else if ($this->_nullDbEmptyStr) $err = 'null-db-empty-str';
      else if ($this->_onCreateImport) $err = 'on-create-import';
      else if ($this->_onDeleteUpdate) $err = 'on-delete-update';
      else if ($this->_orderBy) $err = 'order-by';
      else if ($this->_propagateUpdate) $err = 'propagate-update';
      else if (isset($conf['attributes']['table'])) $err = 'table';
      if ($err) {
        $msg = 'SRA_EntityGenerator::SRA_EntityGenerator: Failed - the entity attribute ' . $err . ' cannot be used in conjunction with ws-db for entity ' . $this->_name;
        $this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
        return;
      }
    }
    
	}
	// }}}
	
  
  // public operations
	
	// {{{ attributeGeneratorToColumn
	/**
	 * Used to convert an SRA_AttributeGenerator to a SRA_SchemaColumn object
	 * @param SRA_AttributeGenerator $generator the SRA_AttributeGenerator to convert
	 * @param SRA_SchemaTable $table the table that this column will belong to
	 * @param SRA_SchemaTable $baseTable the base table for the schema
   * @access  public
	 * @return SRA_SchemaColumn
	 */
	function &attributeGeneratorToColumn(& $generator, & $table, & $baseTable) {
		$column = new SRA_SchemaColumn(array($generator->_name), $generator->_column);
		$column->addReadConstraint($generator->_name, $generator->_constraint);
		$column->setDefault($generator->_default);
		$column->setLazyLoad($generator->_lazyLoad);
		$column->setLazyLoadExclusive($generator->_lazyLoadExclusive);
		$column->setCardinality($generator->_cardinality);
		$column->setCardinalityLower($generator->_cardinalityLower);
		$column->setCardinalityUpper($generator->_cardinalityUpper);
		$column->setColumnType($generator->_columnType);
		$column->setReadOnly($generator->_readOnly);
		$column->setRetrieveFunction($generator->_retrieveFunction);
		$column->setSequence($generator->_sequence);
		$column->setSetFunction($generator->_setFunction);
		$column->setSetOnly($generator->_setOnly);
		$column->setType($generator->_type);
		$column->setValidators($generator->_validators);
		$column->setVars($generator->_vars);
		
		// set foreign table criteria
		if ($table->_name != $baseTable->_name) {
			if ($generator->_orderBy) {
				$table->setOrderConstraint($generator->_orderBy);
			}
			if ($generator->_constraint) {
				$table->setSelectConstraint($generator->_constraint);
			}
		}
		return $column;
	}
	// }}}
  
  
	// {{{ attrIsPersistent
	/**
	 * returns TRUE if $attr is persistent
   * @param string $attr the attribute
   * @access public
	 * @return boolean
	 */
  function attrIsPersistent($attr) {
    return isset($this->_attributeGenerators[$attr]) && !$this->_entityGenerators[$this->_attributeGenerators[$attr]->_type]->_skipPersistence ? TRUE : FALSE;
  }
	// }}}
	
	
	// {{{ checkAttrs
	/**
	 * validates that all attr generators are valid
   * @access  public
	 * @return String
	 */
	function checkAttrs() {
		// check attribute generators
		$keys = array_keys($this->_attributeGenerators);
		foreach ($keys as $key) {
			if (!SRA_AttributeGenerator::isValid($this->_attributeGenerators[$key])) {
				unset($this->_attributeGenerators[$key]);
			}
		}
	}
	// }}}
  
  
	// {{{ excludeAttrFromRender
	/**
	 * Returns true if the $attr specified should be excluded from a render method 
   * invocation (json or xml)
   * @param string $attr the name of the attribute to check
   * @access  public
	 * @return String
	 */
  function excludeAttrFromRender($attr) {
    return in_array($attr, $this->_renderExclude) || ($this->_renderInclude && !in_array($attr, $this->_renderInclude));
  }
  // }}}
  
  
	// {{{ getResources
	/**
	 * returns the resources used by this entity
   * @access  public
	 * @return ResourceBundle
	 */
	function &getResources() { 
    if (!$this->_resourceBundles) {
      $this->_resourceBundles =& SRA_Controller::getAppResources();
      if ($this->_resources) {
        foreach ($this->_resources as $res) {
          $this->_resourceBundles =& SRA_ResourceBundle::merge($this->_resourceBundles, SRA_ResourceBundle::getBundle($res));
        }
      }
    }
    return $this->_resourceBundles;
	}
	// }}}
  
	
	// {{{ generate
	/**
	 * Used to generate this entity
	 * @param SRA_EntityGenerator[] $entityGenerators an array of all of the 
	 * SRA_EntityGenerator objects in the entity model
   * @access  public
	 * @return String
	 */
	function &generate() { 
    $tpl =& SRA_Controller::getAppTemplate();
    
		// set resources
		$tpl->assignByRef(SRA_APP_RB_NAME, $this->getResources());
		
		if (!$this->_skipPersistence && !$this->usesWsDb() && !$this->_customDao && ($schema =& $this->getSchema())) {
			$tpl->assignByRef('schema', $schema);
			$tpl->assignByRef('primaryTable', $schema->getPrimaryTable());
		}
		else if (!$this->_skipPersistence && !$this->usesWsDb() && !$this->_customDao) {
			$msg = "SRA_EntityGenerator::generate: Failed - Unable to retrieve schema for entity $this->_name";
			return SRA_Error::logError($msg, __FILE__, __LINE__);
		}
		
		/* GENERATE VO */
		$this->checkAttrs();
		if (SRA_Error::isError($err =& $this->_generateVO())) {
			return $err;
		}
		
		/* GENERATE DAO */
		$this->checkAttrs();
		if (SRA_Error::isError($err =& $this->_generateDAO())) {
			return $err;
		}
		
	}
	// }}}
  
  
	// {{{ getAopAspects
	/**
	 * Returns all of the SRA_AopAspects for the specified class, method and 
   * when
   * @param string $class the class to return the aspects for (one of the SRA_AOP_CLASS_* constants)
   * @param string $method the name of the method to return the aspects for (w/o parameters or parens)
   * @param string $when the aspect when flag. one of the SRA_AOP_ASPECT_WHEN_* constants
   * @access  public
	 * @return String
	 */
	function getAopAspects($class, $method, $when) {
		$aspects = array();
    $keys = array_keys($this->_aopAspects);
    foreach ($keys as $key) {
      if ($this->_aopAspects[$key]->appliesTo($class, $method, $when)) {
        $aspects[] = $this->_aopAspects[$key];
      }
    }
    return $aspects;
	}
	// }}}
  
  
	// {{{ getAopIntroductions
	/**
	 * Returns all of the SRA_AopIntroductions of the specified type
   * @param string $type a type limiter. if not specified, all introductions 
   * of any type will be returned. must correspond with one of the 
   * SRA_AOP_INTRODUCTION_TYPE_* constants
   * @param string $class a class limiter. if not specified, all introductions 
   * for any class will be returned. must correspond with one of the 
   * SRA_AOP_CLASS_* constants
   * @access  public
	 * @return String
	 */
	function getAopIntroductions($type=FALSE, $class=FALSE) {
		$introductions = array();
    $keys = array_keys($this->_aopIntroductions);
    foreach ($keys as $key) {
      if ($this->_aopIntroductions[$key]->appliesTo($type, $class)) {
        $introductions[] = $this->_aopIntroductions[$key];
      }
    }
    return $introductions;
	}
	// }}}
  
  
	// {{{ getAttributes
	/**
	 * returns the attributes associated with this entity
   * @param string $attr the name of a specific attribute to return the 
   * generator for. if specified, the return value will be a single instance of 
   * SRA_AttributeGenerators
   * @access  public
	 * @return SRA_AttributeGenerators[]
	 */
	function &getAttributes($attr=NULL) {
    $keys = array_keys($this->_attributeGenerators);
    foreach($keys as $key) {
      if (!SRA_AttributeGenerator::isValid($this->_attributeGenerators[$key])) {
        unset($this->_attributeGenerators[$key]);
      }
    }
		return $attr ? $this->_attributeGenerators[$attr] : $this->_attributeGenerators;
	}
	// }}}
  
  
	// {{{ getTypesUsed
	/**
	 * returns all of the types used by this entity and its' corresponding 
   * attributes
   * @param boolean $complexOnly when true only complex (entity) types will be 
   * returned
   * @param array $stack used internally to avoid infinite recursion
   * @param boolean $recursive whether or not to invoke recursively
   * @param boolean $excludeNonIncludeAttrs whether or not to skip entity type 
   * attributes where the skip-include flag is true
   * @access  public
	 * @return string[]
	 */
	function getTypesUsed($complexOnly=FALSE, $stack=NULL, $recursive=TRUE, $excludeNonIncludeAttrs=FALSE) {
    $types = array();
    foreach(array_keys($this->_attributeGenerators) as $key) {
      if ($this->_attributeGenerators[$key] && (!$complexOnly || $this->_attributeGenerators[$key]->isEntity())) {
        
        if ($excludeNonIncludeAttrs && $this->_attributeGenerators[$key]->isEntity() && $this->_attributeGenerators[$key]->_skipInclude) { continue; }
        
        $types[$this->_attributeGenerators[$key]->_type] = TRUE;
        if ($recursive && $this->_attributeGenerators[$key]->isEntity() && (!$stack || !in_array($this->_attributeGenerators[$key]->_type, $stack))) {
          if (!$stack) { $stack = array(); }
          $stack[] = $this->_name;
          foreach($this->_entityGenerators[$this->_attributeGenerators[$key]->_type]->getTypesUsed($complexOnly, $stack) as $type) {
            $types[$type] = TRUE;
          }
        }
      }
    }
		return array_keys($types);
	}
	// }}}	
  
  
	// {{{ getAttrType
	/**
	 * returns the data (or entity) type for the attribute specified
	 * 
   * @param string $attr the attribute to return the type for
   * @access  public
	 * @return string
	 */
  function getAttrType($attr) {
    return isset($this->_attributeGenerators[$attr]) ? $this->_attributeGenerators[$attr]->_type : NULL;
  }
	// }}}
	
	
	// {{{ getDaoClassName
	/**
	 * Returns the DAO class name
   * @access  public
	 * @return String
	 */
	function getDaoClassName() {
		return $this->_name . $this->_daoSuffix;
	}
	// }}}
	
	
	// {{{ getDaoPath
	/**
	 * Returns the path to the DAO for this entity
   * @access  public
	 * @return String
	 */
	function getDaoPath() {
		return $this->_generatePath . '/' . $this->_name . $this->_daoSuffix . '.' . SRA_SYS_PHP_EXTENSION;
	}
	// }}}
  
  
	// {{{ getDtdSubElementName
	/**
	 * Returns the DTD name value for an entity sub-element
   * @param string $subName the sub-element name
   * @access public
	 * @return string
	 */
	function getDtdSubElementName($subName) {
		$name  = $this->_name . strtoupper(substr($subName, 0, 1)) . substr($subName, 1);
		if ($this->_dtdCamelCase) {
			return $name;
		}
		else {
			return SRA_Util::camelCaseToDashes($name);
		}
	}
	// }}}
  
  
	// {{{ getEntityGenerator
	/**
	 * Returns the SRA_EntityGenerator for the $entity specified
   * @param $entity the name of the entity to return the generator for
   * @access  public
	 * @return SRA_EntityGenerator
	 */
	function &getEntityGenerator($entity) {
		return $this->_entityGenerators[$entity];
	}
	// }}}
	
	
	// {{{ getTableAttributes
	/**
	 * Returns an array of all of the attribute generators that utilize the table 
	 * specified
   * @access  public
	 * @return SRA_AttributeGenerator[]
	 */
	function &getTableAttributes($table) {
		$generators = array();
		$keys = array_keys($this->_attributeGenerators);
		foreach($keys as $key) {
			if ($this->_attributeGenerators[$key]->_table == $table) {
				$generators[$key] =& $this->_attributeGenerators[$key];
			}
		}
		return $generators;
	}
	// }}}
	
	
	// {{{ getVoClassName
	/**
	 * Returns the VO class name for this entity
   * @access  public
	 * @return String
	 */
	function getVoClassName() {
		return $this->_name . $this->_voSuffix;
	}
	// }}}
	
	
	// {{{ getVoPath
	/**
	 * Returns the path to the VO for this entity
   * @access  public
	 * @return String
	 */
	function getVoPath() {
		return $this->_generatePath . '/' . $this->_name . $this->_voSuffix . '.' . SRA_SYS_PHP_EXTENSION;
	}
	// }}}
	
	// {{{ getIncludes
	/**
	 * Returns all of the includes for the entity
   * @access  public
	 * @return String[]
	 */
	function getIncludes() {
    $includes = array();
    $aopIntroductions =& $this->getAopIntroductions(SRA_AOP_INTRODUCTION_TYPE_INCLUDE, SRA_AOP_CLASS_VO);
    $keys = array_keys($aopIntroductions);
    foreach($keys as $key) {
      $includes[] = $aopIntroductions[$key]->getValue();
    }
    foreach($this->getTypesUsed(TRUE, NULL, FALSE, TRUE) as $type) {
      $includes[] = $type . $this->_voSuffix . '.' . SRA_SYS_PHP_EXTENSION;
    }
		return $includes;
	}
	// }}}
	
	// {{{ getPrimaryKeyAttribute
	/**
	 * Returns the primary key attribute for this entity
   * @access  public
	 * @return SRA_AttributeGenerator
	 */
	function &getPrimaryKeyAttribute() {
		return $this->_attributeGenerators[$this->_primaryKey];
	}
	// }}}
	
	
	// {{{ getSchema
	/**
	 * Returns an array of the names of all the attributes that should be tracked
	 * 
   * @access  public
	 * @return SRA_EntitySchema  or -1 if loading or FALSE if non-persistent
	 */
	function &getSchema() {
		// schema is currently loading, return -1 to indicate this
		if ($this->_schemaLoading) {
			$this->_schemaRecursionCount++;
			if ($this->_schemaRecursionCount == SRA_ENTITY_GENERATOR_MAX_SCHEMA_RECURSION) {
				$msg = "SRA_EntityGenerator::getSchema: Failed - Recursion limit SRA_ENTITY_GENERATOR_MAX_SCHEMA_RECURSION hit for entity $this->_name";
				SRA_Error::logError($msg, __FILE__, __LINE__);
				exit;
			}
			return -1;
		}
		// schema is already loaded, return
		else if (isset($this->_schema)) {
			return $this->_schema;
		}
		// non-persistent entity, no schema to return
		else if ($this->_skipPersistence || $this->_customDao || $this->_abstract) {
			return FALSE;
		}
		
		// load schema
		$this->_schemaLoading = TRUE;
		$this->_schema = new SRA_EntitySchema ($this->_name);
		$this->_schema->setDbRefIntegrity($this->_dbRefIntegrity);
		$this->_schema->setDdlCamelCase($this->_ddlCamelCase);
		$this->_schema->setDdlUpperCase($this->_ddlUpperCase);
		$this->_schema->setDtdCamelCase($this->_dtdCamelCase);
		$tables = array();
		$tables[$this->_table] = new SRA_SchemaTable($this->_table);
		$tables[$this->_table]->setDeleteConstraint($this->_onDeleteUpdate);
		$tables[$this->_table]->setOrderConstraint($this->_orderBy);
		$pk =& $this->getPrimaryKeyAttribute();
		$tables[$this->_table]->setPrimaryKey($pk->_column);
		$tables[$this->_table]->setPrimary(TRUE);
		$tables[$this->_table]->setSelectConstraint($this->_constraint);
		$keys = array_keys($this->_attributeGenerators);
		while (count($keys)) {
			$temp = array_keys($keys);
			for($i=0; $i<count($temp); $i++) {
				$key = $keys[$temp[$i]];
				if ($this->_attributeGenerators[$key]->_skipPersistence || $this->_attributeGenerators[$key]->_customDao || !$key) {
					unset($keys[$temp[$i]]);
					continue;
				}
        // SRA_Error::logError("EVAL ATTR " . $this->_attributeGenerators[$key]->_name . " FOR ENTITY " . $this->_name, __FILE__, __LINE__);
				$atable = $this->_attributeGenerators[$key]->_table ? $this->_attributeGenerators[$key]->_table : $this->_table;
				if (!isset($tables[$atable])) {
					$tables[$atable] = new SRA_SchemaTable($atable);
					$pkCol = $pk->_column;
					if ($this->_attributeGenerators[$key]->_tablePkColumn) {
						$pkCol = $this->_attributeGenerators[$key]->_tablePkColumn;
					}
					
					if ($this->_attributeGenerators[$key]->_table && $this->_attributeGenerators[$key]->_table != $this->_table) {
						$column =& $this->attributeGeneratorToColumn($pk, $tables[$atable], $tables[$this->_table]);
						$column->setName($pkCol);
						$column->setReferences($this->_table . '(' . $pk->_column . ')');
						$column->setSequence(FALSE);
						if (!$this->_attributeGenerators[$key]->isEntity() && (!$this->_attributeGenerators[$key]->_onDeleteCascadeSet || ($this->_attributeGenerators[$key]->_onDeleteCascadeSet && $this->_attributeGenerators[$key]->_onDeleteCascade))) {
							$column->setOnDeleteCascade(TRUE);
						}
						$tables[$atable]->addColumn($column);
					}
          else {
            $tables[$atable]->setPrimaryKey($pkCol);
          }
				}
        // add attribute index
        if ($this->_attributeGenerators[$key]->_indexed && $this->_attributeGenerators[$key]->_column && (!$this->_attributeGenerators[$key]->_table || $this->_attributeGenerators[$key]->_table == $tables[$atable]->getName())) {
          $tables[$atable]->addIndex(new SRA_SchemaIndex($this->_attributeGenerators[$key]->_column, $tables[$atable]->getName() . '_' . $this->_attributeGenerators[$key]->_column . '_idx', $tables[$atable]->getName()));
        }
				// base scalar attribute
				if (!$this->_attributeGenerators[$key]->isEntity()) {
					$column =& $this->attributeGeneratorToColumn($this->_attributeGenerators[$key], $tables[$atable], $tables[$this->_table]);
          if (isset($tables[$atable]->_columns[$column->getName()])) { $tables[$atable]->_columns[$column->getName()]->setBaseAttribute($column->getBaseAttribute()); }
					$tables[$atable]->addColumn($column);
				}
				// entity attribute
				else {
					if (!count($mappings =& $this->_attributeGenerators[$key]->getMappedAttributes(TRUE))) {
						// handle attribute nesting
						if (count($this->_attributeGenerators[$key]->_attributeGenerators)) {
							$akeys = array_keys($this->_attributeGenerators[$key]->_attributeGenerators);
							foreach ($akeys as $akey) {
								$column =& $this->attributeGeneratorToColumn($this->_attributeGenerators[$key]->_attributeGenerators[$akey], $tables[$atable], $tables[$this->_table]);
								$sattributes = $column->getAttributes();
								$sakeys = array_keys($sattributes);
								foreach ($sakeys as $sakey) {
									$column->addAttribute($this->_attributeGenerators[$key]->_name . '_' . $sattributes[$sakey]);
								}
								$tables[$atable]->addColumn($column);
							}
						}
						
						// validate type and type
						if ($this->_attributeGenerators[$key]->_type && !isset($this->_entityGenerators[$this->_attributeGenerators[$key]->_type])) {
							$this->_schemaLoading = FALSE;
							$msg = "SRA_EntityGenerator::getSchema: Failed - Invalid _type for attribute ${key}: Type - " . $this->_attributeGenerators[$key]->_type;
							return SRA_Error::logError($msg, __FILE__, __LINE__);
						}
						
						// set primary key(s)
						
						// add schema for entity type attribute
						$typeKey = $this->_attributeGenerators[$key]->_type;
						if (isset($this->_entityGenerators[$typeKey])) {
							$typePkAttr =& $this->_entityGenerators[$typeKey]->getPrimaryKeyAttribute();
							$column =& $this->attributeGeneratorToColumn($this->_attributeGenerators[$key], $tables[$atable], $tables[$this->_table]);
							$column->updateAttributeName($this->_attributeGenerators[$key]->_name, $this->_attributeGenerators[$key]->_name . '_' . $typePkAttr->_name);
							$column->setType($typePkAttr->_type);
              $column->setValidators($typePkAttr->_validators);
              $column->setVars($typePkAttr->_vars);
							$column->setOnDeleteCascade($this->_attributeGenerators[$key]->_onDeleteCascade);
							$overwrite = FALSE;
							
							// foreign entity primary key in primary table
							if ((!$this->_attributeGenerators[$key]->_table || $this->_attributeGenerators[$key]->_table == $this->_table) && !$this->_attributeGenerators[$key]->_tablePkColumn && !$this->_attributeGenerators[$key]->_cardinality) {
								$column->setReferences($this->_entityGenerators[$typeKey]->_table . '(' . $typePkAttr->_column . ')');
							}
							// entity primary key in foreign entity primary table
							else if ((!$this->_attributeGenerators[$key]->_table || $this->_attributeGenerators[$key]->_table == $this->_entityGenerators[$typeKey]->_table) && ($this->_attributeGenerators[$key]->_tablePkColumn || $this->_attributeGenerators[$key]->_cardinality)) {
								$atable = $this->_entityGenerators[$typeKey]->_table;
								if (!isset($tables[$atable])) {
									$tables[$atable] = new SRA_SchemaTable($atable);
								}
								$column->updateAttributeName($this->_attributeGenerators[$key]->_name . '_' . $typePkAttr->_name, $this->_attributeGenerators[$key]->_name);
								$column->setBaseAttribute($pk->_name);
                $column->setName($this->_attributeGenerators[$key]->_tablePkColumn ? $this->_attributeGenerators[$key]->_tablePkColumn : $pk->_column);
                $column->setType($pk->_type);
                $column->setValidators($pk->_validators);
                $column->setVars($pk->_vars);
								$column->setReferences($this->_table . '(' . $pk->_column . ')');
                $overwrite = TRUE;
							}
							// foreign entity primary key in external table
							else if ($this->_attributeGenerators[$key]->_table && $this->_attributeGenerators[$key]->_table != $this->_table && $this->_attributeGenerators[$key]->_table != $this->_entityGenerators[$typeKey]->_table) {
								$column->setReferences($this->_entityGenerators[$typeKey]->_table . '(' . $typePkAttr->_column . ')');
								if ($this->_attributeGenerators[$key]->_ddlNameGenerated) {
									$column->setName($typePkAttr->_column);
								}
                $tables[$atable]->setPrimaryKey($this->_attributeGenerators[$key]->_tablePkColumn ? $this->_attributeGenerators[$key]->_tablePkColumn : $pk->_column);
                $tables[$atable]->addPrimaryKey($column->getName());
								$column->setOnDeleteCascade(TRUE);
								$overwrite = TRUE;
							}
							
              $oldColumn =& $tables[$atable]->_columns[$column->getName()];
							$tables[$atable]->addColumn($column, $overwrite);
              // restore base attribute name
              if ($oldColumn && $overwrite && $this->_attributeGenerators[$key]->_cardinality) { $tables[$atable]->_columns[$column->getName()]->setBaseAttribute($oldColumn->getBaseAttribute()); }
              if ($oldColumn && !$overwrite && !$this->_attributeGenerators[$key]->_cardinality) { $tables[$atable]->_columns[$column->getName()]->setBaseAttribute($column->getBaseAttribute()); }
						}
					}
					else {
						$mkeys = array_keys($mappings);
						foreach ($mkeys as $mkey) {
							$column =& $this->attributeGeneratorToColumn($mappings[$mkey], $tables[$atable], $tables[$this->_table]);
							$tables[$atable]->addColumn($column);
						}
					}
				}
				unset($keys[$temp[$i]]);
			}
		}
		$this->_schema->addTable($tables);
		$this->_schemaLoading = FALSE;
		//echo "SCHEMA FOR " . $this->_name . "\n";
		//print_r($this->_schema);
		return $this->_schema;
	}
	// }}}
  
  
	// {{{ getDtdAttributes
	/**
	 * Returns the attributes that should be attributes within this entity's DTD
   * @param boolean $includeSetOnly whether or not to include setOnly attributes
   * @access  public
	 * @return AttributeGenerator[]
	 */
	function &getDtdAttributes($includeSetOnly=FALSE) {
    if (!isset($this->_dtdAttributes) || $this->_lastDtdAttributesSetOnly != $includeSetOnly) {
      $this->_lastDtdAttributesSetOnly = $includeSetOnly;
      $this->_dtdAttributes = array();
      $subElements =& $this->getDtdElements($includeSetOnly);
      $keys = array_keys($this->_attributeGenerators);
      foreach ($keys as $key) {
        if (!$this->excludeAttrFromRender($key) && SRA_AttributeGenerator::isValid($this->_attributeGenerators[$key]) && !isset($subElements[$key]) && !$this->_attributeGenerators[$key]->_circularRef && ($includeSetOnly || !$this->_attributeGenerators[$key]->_setOnly)) {
          $this->_dtdAttributes[$key] =& $this->_attributeGenerators[$key];
        }
      }
    }
    return $this->_dtdAttributes;
	}
	// }}}
  
  
	// {{{ getDtdElements
	/**
	 * Returns the attributes that should be sub-elements within this entity's DTD
   * @param boolean $includeSetOnly whether or not to include setOnly attributes
   * @access  public
	 * @return AttributeGenerator[]
	 */
	function &getDtdElements($includeSetOnly=FALSE) {
    if (!isset($this->_dtdSubElements) || $this->_lastDtdElementsSetOnly != $includeSetOnly) {
      $this->_lastDtdElementsSetOnly = $includeSetOnly;
      $keys = array_keys($this->_attributeGenerators);
      foreach ($keys as $key) {
        if (!$this->excludeAttrFromRender($key) && SRA_AttributeGenerator::isValid($this->_attributeGenerators[$key]) && !$this->_attributeGenerators[$key]->_circularRef && ($includeSetOnly || !$this->_attributeGenerators[$key]->_setOnly) && !$this->_attributeGenerators[$key]->_xmlUseAttribute) {
          $this->_dtdSubElements[$key] =& $this->_attributeGenerators[$key];
        }
      }
    }
    return $this->_dtdSubElements;
	}
	// }}}
  
  
	// {{{ hasCardinality
	/**
	 * returns TRUE if the $attr specified is valid for this entity and has 
   * cardinality
	 * 
   * @param string $attr the attribute to check for
   * @access  public
	 * @return boolean
	 */
  function hasCardinality($attr) {
    return isset($this->_attributeGenerators[$attr]) && $this->_attributeGenerators[$attr]->_cardinality;
  }
	// }}}
  
  
	// {{{ hasAttribute
	/**
	 * returns TRUE if this entity contains the attribute $attr
	 * 
   * @param string $attr the attribute to check for
   * @access  public
	 * @return boolean
	 */
  function hasAttribute($attr) {
    return isset($this->_attributeGenerators[$attr]);
  }
	// }}}
  
  
	// {{{ isPrimaryTableAttr
	/**
	 * returns TRUE if $attr is a non-cardinality attribute stored in the primary 
   * entity table
   * @access  public
	 * @return boolean
	 */
	function isPrimaryTableAttr($attr) {
    $keys = array_keys($this->_attributeGenerators);
    foreach ($keys as $key) {
      if ($this->_attributeGenerators[$key]->_name == $attr && (!$this->_attributeGenerators[$key]->_table || $this->_attributeGenerators[$key]->_table == $this->_table) && (!$this->_attributeGenerators[$key]->_cardinality || !$this->_attributeGenerators[$key]->isEntity())) {
        return TRUE;
      }
    }
    return FALSE;
	}
	// }}}
  
  
	// {{{ isFile
	/**
	 * returns TRUE if the $attr specified is valid for this entity and is a file
	 * 
   * @param string $attr the attribute to check for
   * @access  public
	 * @return boolean
	 */
  function isFile($attr) {
    return isset($this->_attributeGenerators[$attr]) && $this->_attributeGenerators[$attr]->_isFile;
  }
	// }}}
  
  
	// {{{ usesFiles
	/**
	 * returns TRUE if this entity or any of its' sub-entities use file type 
   * attributes
   * @param array $stack used internally to avoid infinite recursion
   * @access  public
	 * @return boolean
	 */
	function usesFiles($stack=NULL) {
    foreach(array_keys($this->_attributeGenerators) as $key) {
      if ($this->_attributeGenerators[$key]->_isFile) {
        return TRUE;
      }
      else if ($this->_attributeGenerators[$key] && $this->_attributeGenerators[$key]->isEntity() && (!$stack || !in_array($this->_attributeGenerators[$key]->_type, $stack))) {
        if (!$stack) { $stack = array(); }
        $stack[] = $this->_name;
        
        if ($this->_entityGenerators[$this->_attributeGenerators[$key]->_type]->usesFiles($stack)) {
          return TRUE;
        }
      }
    }
		return FALSE;
	}
	// }}}
  
	// {{{ usesWsDb
	/**
	 * returns TRUE if this entity uses a web service db for persistence
   * @access  public
	 * @return boolean
	 */
  function usesWsDb() {
    return $this->_wsDb && $this->_wsDbName ? TRUE : FALSE;
  }
	// }}}
  
  
  // private operations
	// {{{ _generateDAO
	/**
	 * Used to generate the DAO for this entity
	 * @param file $fp the file pointer to write to, if not specified, a new fp 
	 * will be opened
   * @access  public
	 * @return void
	 */
	function &_generateDAO($fp = FALSE) {
		if (!$this->_skipPersistence && !$this->_customDao) {
			if (!$fp) {
				$closeFp = TRUE;
				$fileName = $this->getDaoPath();
				// attempt to create new file
				SRA_Util::printDebug("SRA_EntityGenerator::_generateDAO - Attempting to create DAO file ${fileName}", SRA_Controller::isSysInDebug(), __FILE__, __LINE__);
				if ((file_exists($fileName) && !unlink($fileName)) || ($fp = fopen($fileName, 'w')) === FALSE) {
					$msg = "SRA_EntityGenerator::_generateDAO: Failed - Pointer to file ${fileName} could not be opened";
					return SRA_Error::logError($msg, __FILE__, __LINE__);
				}
			}
			$tpl =& SRA_Controller::getAppTemplate();
			$tpl->assignByRef('entity', $this);
			$tpl->assignByRef('className', $this->getDaoClassName());
			$tpl->assignByRef('voClassName', $this->getVoClassName());
			$includes = array($this->_name . $this->_voSuffix . '.' . SRA_SYS_PHP_EXTENSION);
			$tpl->assignByRef('includes', $includes);
			$tpl->assignByRef('primaryKey', $this->getPrimaryKeyAttribute());
			fwrite($fp, $tpl->fetch(dirname(realpath(__FILE__)) . ($this->usesWsDb() ? '/dao-ws.tpl' : '/dao.tpl')));
			if ($closeFp) {
				fclose($fp);
        chmod($fileName, 0666);
			}
			$daoClass = $this->_name . $this->_daoSuffix;
			$daoFile = $fileName;
		}
		else {
			$daoClass = $this->_dao;
			$daoFile = $this->_daoFile;
			SRA_Util::printDebug("SRA_EntityGenerator::_generateDAO - Skipping DAO for " . $this->_name . " because fixed DAO has been specified or entity is not persistent", SRA_Controller::isSysInDebug(), __FILE__, __LINE__);
		}
		if (!$this->_skipPersistence || $this->_dao) {
			SRA_DaoFactory::registerDAO($this->_name, $daoClass, $daoFile);
		}
	}
	// }}}
	
	// {{{ _generateVO
	/**
	 * Used to generate the VO for this entity
	 * @param file $fp the file pointer to write to, if not specified, a new fp 
	 * will be opened
   * @access  public
	 * @return String
	 */
	function &_generateVO($fp = FALSE) {
		if (!$fp) {
			$closeFp = TRUE;
			$fileName = $this->getVoPath();
			// attempt to create new file
			SRA_Util::printDebug("SRA_EntityGenerator::_generateVO - Attempting to create VO file ${fileName}", SRA_Controller::isSysInDebug(), __FILE__, __LINE__);
			if ((file_exists($fileName) && !unlink($fileName)) || ($fp = fopen($fileName, 'w')) === FALSE) {
				$msg = "SRA_EntityGenerator::_generateVO: Failed - Pointer to file ${fileName} could not be opened";
				return SRA_Error::logError($msg, __FILE__, __LINE__);
			}
		}
		$tpl =& SRA_Controller::getAppTemplate();
		$tpl->assignByRef('entity', $this);
		$tpl->assignByRef('className', $this->getVoClassName());
		$tpl->assignByRef('primaryKey', $this->getPrimaryKeyAttribute());
		fwrite($fp, $tpl->fetch(dirname(realpath(__FILE__)) . '/vo.tpl'));
		if ($closeFp) {
			fclose($fp);
      chmod($fileName, 0666);
		}
	}
	// }}}
	
	
	// {{{ isValid()
	/**
	 * Static method that returns true if the object parameter is a SRA_Generator object.
	 *
	 * @param  Object $object The object to validate
	 * @access	public
	 * @return	boolean
	 */
	function isValid( & $object ) {
		return (is_object($object) && (!isset($object->err) || !SRA_Error::isError($object->err)) && strtolower(get_class($object)) == 'sra_entitygenerator');
	}
	// }}}
  
}
// }}}
?>
Return current item: Sierra-php PHP Application Framework