<?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_AttributeValidator.php');
require_once('model/SRA_AttrMapping.php');
require_once('model/SRA_AttributeThumbnail.php');
// }}}
// {{{ Constants
/**
* The 'required' validation constraint key
* @type string
*/
define('SRA_ATTRIBUTE_GENERATOR_REQUIRED', 'required');
/**
* The prefix to use for attribute values within the dtd (this value follows
* the entity name)
* @type string
*/
define('SRA_ATTRIBUTE_DTD_ATTR_PREFIX', 'Attr');
// }}}
// {{{ SRA_AttributeGenerator
/**
* Used to generate an entity model attribute
*
* @author Jason Read <hide@address.com>
* @package sierra.model
*/
class SRA_AttributeGenerator extends SRA_Generator {
// {{{ Attributes
// public attributes
// private attributes
var $_aggregate;
var $_aggregateCardinality = FALSE;
var $_aggregatePrefix;
var $_name;
var $_apiResource;
var $_attrMapping;
var $_attrMappings;
var $_cardinality;
var $_cardinalityErr;
var $_cardinalityLower;
var $_cardinalityUnique;
var $_cardinalityUpper;
var $_column;
var $_columnType;
var $_constraint;
var $_dateFormat;
var $_default;
var $_hasDefault;
var $_ddlCamelCase;
var $_ddlUpperCase;
var $_dtdCamelCase;
var $_dtdName;
var $_entityGenerator;
var $_entityGenerators;
var $_fileIconAttr;
var $_fileIconDir;
var $_fileIndexAttr;
var $_fileUriAttr;
var $_fileUriKbAttr;
var $_fileUriMbAttr;
var $_fileProcessor;
var $_indexed;
var $_jsonView;
var $_lazyLoad = FALSE;
var $_lazyLoadExclusive = FALSE;
var $_nestedPks;
var $_daoSuffix = FALSE;
var $_globalName;
var $_isFile;
var $_mapped;
var $_mappedExclude;
var $_mappedInclude;
var $_mappedPostfix;
var $_mappedPrefix;
var $_mappedResourcePostfix;
var $_mappedResourcePrefix;
var $_matchUserId;
var $_nullDbEmptyStr;
var $_voSuffix = FALSE;
var $_onDeleteCascade;
var $_onDeleteCascadeSet = FALSE;
var $_onRemoveDelete;
var $_orderBy;
var $_primaryKey = FALSE;
var $_readOnly;
var $_recursiveLink;
var $_renderDisplOption;
var $_renderExclude;
var $_renderInclude;
var $_required = FALSE;
var $_resource;
var $_resourceHelp;
var $_retrieveFunction;
var $_sequence = FALSE;
var $_setConvert;
var $_setFunction;
var $_setOnly;
var $_singleOption = FALSE;
var $_skipDefaultViews;
var $_skipInclude;
var $_skipPersistence;
var $_skipWsdl;
var $_table;
var $_tablePkColumn = FALSE;
var $_thumbnails = array();
var $_type;
var $_typeErrResource;
var $_useReference;
var $_msgs;
var $_unionLink;
var $_vars;
var $_views;
var $_validators;
var $_xmlUseAttribute;
var $_xmlView;
// }}}
// {{{ Operations
// constructor(s)
// {{{ SRA_AttributeGenerator
/**
* Creates a new SRA_AttributeGenerator with the configuration specified
* @param array $conf associative array of attribute configuration values
* @access private
*/
function SRA_AttributeGenerator(& $conf, $ddlCamelCase, $dtdCamelCase, & $entityGenerator, $types) {
// determine and validate resource
$prefixes = array('attribute', $entityGenerator->_name, $entityGenerator->_resource, 'text');
$finalResource = isset($conf['attributes']['type']) && !SRA_EntityModeler::isValidType($conf['attributes']['type']) ? $conf['attributes']['type'] : NULL;
$finalResourceHelp = $finalResource ? $finalResource . '-help' : NULL;
$this->_resource = $this->getResource($conf, $entityGenerator->_resources, $prefixes, '', $finalResource);
$this->_resourceHelp = $this->getHelpResource($conf, $entityGenerator->_resources, $prefixes, '', $finalResourceHelp);
// validate required key
if (!isset($conf['attributes']['key'])) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - Missing 'key' value for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
// set type
if (isset($conf['attributes']['is-file']) && $conf['attributes']['is-file'] == '1' && !isset($conf['attributes']['type'])) {
if ($entityGenerator->_fileHandling == SRA_FILE_ATTRIBUTE_TYPE_DB) {
$conf['attributes']['type'] = SRA_DATA_TYPE_BLOB;
$this->_type = SRA_DATA_TYPE_BLOB;
if ($conf['attributes']['table'] && $conf['attributes']['table'] != $entityGenerator->_table && !isset($conf['attributes']['lazy-load'])) {
$conf['attributes']['lazy-load'] = '1';
}
else if ((!$conf['attributes']['table'] || $conf['attributes']['table'] == $entityGenerator->_table) && !isset($conf['attributes']['lazy-load-exclusive'])) {
$conf['attributes']['lazy-load-exclusive'] = '1';
}
}
else {
$conf['attributes']['max-length'] = 255;
}
}
$this->_matchUserId = isset($conf['attributes']['match-user-id']) ? $conf['attributes']['match-user-id'] : $entityGenerator->_matchUserId;
$this->_sequence = isset($conf['attributes']['sequence']) && $conf['attributes']['sequence'] == '1';
if (isset($conf['attributes']['type']) && strtolower($conf['attributes']['type']) == 'text') { $conf['attributes']['type'] = SRA_DATA_TYPE_STRING; }
if (isset($conf['attributes']['type'])) {
$this->_type = $conf['attributes']['type'];
}
else {
$this->_type = SRA_DATA_TYPE_STRING;
}
if ($this->_sequence) {
$this->_type = SRA_DATA_TYPE_INT;
}
// attribute mappings
$this->_mappedPostfix = isset($conf['attributes']['mapped-postfix']) ? $conf['attributes']['mapped-postfix'] : '';
$this->_mappedResourcePostfix = isset($conf['attributes']['mapped-resource-postfix']) ? $conf['attributes']['mapped-resource-postfix'] : '';
$this->_mappedPrefix = isset($conf['attributes']['mapped-prefix']) ? $conf['attributes']['mapped-prefix'] : '';
$this->_mappedResourcePrefix = isset($conf['attributes']['mapped-resource-prefix']) ? $conf['attributes']['mapped-resource-prefix'] : '';
$this->_attrMappings = array();
if (isset($conf['attr-mapping']) && $conf['attr-mapping']) {
$keys = array_keys($conf['attr-mapping']);
foreach ($keys as $key) {
$col = $this->getDdlName($conf['attr-mapping'][$key]['attributes']['column'], $key, $entityGenerator->_ddlUpperCase, $this->_mappedPrefix, $this->_mappedPostfix);
$this->_attrMappings[$key] = new SRA_AttrMapping($key, $col, $conf['attr-mapping'][$key]['attributes']['resource'], $conf['attr-mapping'][$key]['attributes']['resource-help'], $this->_mappedResourcePostfix, $this->_mappedResourcePrefix);
if (SRA_Error::isError($this->_attrMappings[$key])) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - attr-mapping ${key} produced error for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
}
}
if (!count($this->_attrMappings)) {
$this->_attrMappings = FALSE;
}
// validate column(s)
if (isset($conf['attributes']['table']) && $conf['attributes']['table']) {
$tableName = $conf['attributes']['table'];
}
else {
$tableName = $entityGenerator->_table;
}
// default lazy-load to True for entities and table related attributes
if (!$this->_sequence && !isset($conf['attributes']['lazy-load']) && (isset($conf['attributes']['table']) || !SRA_EntityModeler::isValidType($this->_type)) && !$this->_attrMappings && (!isset($conf['attributes']['mapped']) || $conf['attributes']['mapped'] != '1')) {
$conf['attributes']['lazy-load'] = '1';
}
// validate lazy load
if (!isset($conf['attributes']['table']) && !isset($this->_type) && $conf['attributes']['lazy-load']) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - Attribute can only be 'lazy-loaded' if external table or entity type is specified for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
// validate cardinality
if (isset($conf['attributes']['cardinality']) && $conf['attributes']['cardinality']) {
$pieces = explode('..', $conf['attributes']['cardinality']);
if ($pieces[1] === '*') {
$pieces[1] = SRA_MAX_INT_VAL;
}
$pieces[0] = (int) $pieces[0];
$pieces[1] = (int) $pieces[1];
if (!count($pieces) == 2 || !is_int($pieces[0]) || !is_int($pieces[1]) || $pieces[0] < 0 || $pieces[1] < 0 || $pieces[0] > $pieces[1]) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - Invalid cardinality specified '" . $conf['attributes']['cardinality'] . "' for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
else {
// must specify both add-error-resource and remove-error-resource if upper bound > 1
if (!isset($conf['attributes']['cardinality-err-resource'])) {
$this->_cardinalityErr = $entityGenerator->_sysErrResource;
}
else {
if (!SRA_Generator::validateResource($conf['attributes']['cardinality-err-resource'], $entityGenerator->_resources)) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - cardinality-err-resource '" . $conf['attributes']['cardinality-err-resource'] . "' is not valid for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
$this->_cardinalityErr = $conf['attributes']['cardinality-err-resource'];
}
$this->_cardinalityLower = $pieces[0];
$this->_cardinalityUpper = $pieces[1];
if ($this->_cardinalityUpper > 1) {
$this->_cardinality = TRUE;
}
// scalar attribute stored in same table as entity
if (SRA_EntityModeler::isValidType($this->_type) && ($tableName == $entityGenerator->_table)) {
$this->_type = SRA_DATA_TYPE_STRING;
if (!isset($conf['attributes']['max-length'])) { $conf['attributes']['max-length'] = 255; }
$this->_aggregateCardinality = TRUE;
}
}
}
// validate constraint
if (!$tableName && isset($conf['attributes']['constraint']) && $conf['attributes']['constraint'] && !$this->_cardinality) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - Constraint specified but no table for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
// validate order-by
if (isset($conf['attributes']['order-by']) && $conf['attributes']['order-by'] && !$conf['attributes']['table'] && !$this->_cardinality) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - order-by attributes must be stored in a separate table " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
// validate api-resource
if (isset($conf['attributes']['api-resource']) && !SRA_Generator::validateResource($conf['attributes']['api-resource'], $entityGenerator->_resources)) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - api-resource '" . $conf['attributes']['api-resource'] . "' is not valid for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
// validate type
if (!SRA_EntityModeler::isValidType($this->_type) && !in_array($this->_type, $types)) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - Type '" . $this->_type . "' is not a valid database or entity type. attribute: " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
// validate msg
$this->_msgs = array();
if (isset($conf['msg'])) {
$keys = array_keys($conf['msg']);
foreach ($keys as $key) {
if (!$conf['msg'][$key]['attributes']['resource']) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - msg '${key}' does not have required 'resource' attribute for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
else if (!SRA_Generator::validateResource($conf['msg'][$key]['attributes']['resource'], $entityGenerator->_resources)) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - resource '" . $conf['msg'][$key]['attributes']['resource'] . "' for msg '${key}' is not valid for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
$this->_msgs[$key] = $conf['msg'][$key]['attributes']['resource'];
}
}
// add enclosing entity msgs
$this->_msgs = array_merge($entityGenerator->_msgs, $this->_msgs);
// validate var
$this->_vars = array();
if (isset($conf['var']) && $conf['var']) {
$keys = array_keys($conf['var']);
foreach ($keys as $key) {
if (!isset($conf['var'][$key]['attributes']['value'])) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - var '${key}' does not have required 'value' attribute for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
$this->_vars[$key] = $conf['var'][$key]['attributes']['value'];
}
}
// dynamic depends
if (isset($conf['attributes']['max-length'])) {
$conf['attributes']['depends'] = isset($conf['attributes']['depends']) ? $conf['attributes']['depends'] . ' maxLength' : 'maxLength';
$this->_vars['maxLength'] = $conf['attributes']['max-length'];
}
if (isset($conf['attributes']['min-length'])) {
$conf['attributes']['depends'] = isset($conf['attributes']['depends']) ? $conf['attributes']['depends'] . ' minLength' : 'minLength';
$this->_vars['minLength'] = $conf['attributes']['min-length'];
}
// views
$this->_skipDefaultViews = isset($conf['attributes']['skip-default-views']) && $conf['attributes']['skip-default-views'] == '1';
if (!$this->_skipDefaultViews) { $this->_mergeDefaultViews($conf, $entityGenerator->_defaultViews, $this->_type, $conf['attributes']['key'], $entityGenerator->_name, $conf['attributes']['cardinality'], $conf['attributes']['depends']); }
if (SRA_Error::isError($views =& SRA_Generator::getViews($conf['view'], $entityGenerator->_viewProcessors, TRUE))) {
return $views;
}
if (is_array($views) && count($views)) {
SRA_EntityView::mergeExtends($views, $entityGenerator->_views);
SRA_EntityView::mergeExtends($views, $entityGenerator->_globalViews);
SRA_EntityView::setDefaultView($views);
$this->_views =& $views;
}
//validators
$this->_validators = array();
if ($conf['attributes']['depends']) {
$validators = explode(' ', $conf['attributes']['depends']);
foreach ($validators as $validator) {
$validator = trim($validator);
if ($validator == 'required') {
$this->_required = TRUE;
}
if ($validator == 'option') {
$this->_singleOption = TRUE;
}
if (!SRA_AttributeValidator::isValidValidator($validator, $this->_vars, TRUE)) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - validator '${validator}' is not valid for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
else if (!isset($this->_msgs[$validator])) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - No error message specified for validator '${validator}' in attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
$this->_validators[] = $validator;
}
}
// add data type validators (automatic depending on type)
if (!in_array('boolean', $this->_validators) && $this->_type == SRA_DATA_TYPE_BOOLEAN) {
$this->_validators[] = 'boolean';
if (!isset($this->_msgs['boolean']) && isset($this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY])) {
$this->_msgs['boolean'] = $this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY];
}
}
else if (!in_array('date', $this->_validators) && ($this->_type == SRA_DATA_TYPE_DATE || $this->_type == SRA_DATA_TYPE_TYPE)) {
$this->_validators[] = 'date';
if (!isset($this->_msgs['date']) && isset($this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY])) {
$this->_msgs['date'] = $this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY];
}
}
else if (!in_array('integer', $this->_validators) && $this->_type == SRA_DATA_TYPE_INT) {
$this->_validators[] = 'integer';
if (!isset($this->_msgs['integer']) && isset($this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY])) {
$this->_msgs['integer'] = $this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY];
}
}
else if (!in_array('numeric', $this->_validators) && $this->_type == SRA_DATA_TYPE_FLOAT) {
$this->_validators[] = 'numeric';
if (!isset($this->_msgs['numeric']) && isset($this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY])) {
$this->_msgs['numeric'] = $this->_msgs[SRA_ATTRIBUTE_TYPE_MSG_KEY];
}
}
//validate type-err-resource
if (isset($this->_type) && !isset($conf['attributes']['type-err-resource'])) {
$conf['attributes']['type-err-resource'] = $entityGenerator->_sysErrResource;
}
if (!SRA_EntityModeler::isValidType($this->_type) && (!$conf['attributes']['type-err-resource'] || !SRA_Generator::validateResource($conf['attributes']['type-err-resource'], $entityGenerator->_resources))) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - type-err-resource is required but not present or invalid for attribute " . $conf['attributes']['key'] . ' Resource: ' . $conf['attributes']['type-err-resource'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
$this->_isFile = isset($conf['attributes']['is-file']) && $conf['attributes']['is-file'] == '1';
// file icon dir
if ($this->_isFile && isset($conf['attributes']['file-icon-dir']) && !file_exists($conf['attributes']['file-icon-dir']) && !file_exists(SRA_Controller::getAppDir() . '/' . $conf['attributes']['file-icon-dir'])) {
$msg = 'SRA_AttributeGenerator::SRA_AttributeGenerator: 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 ($this->_isFile && isset($conf['attributes']['file-icon-dir'])) {
$this->_fileIconDir = $conf['attributes']['file-icon-dir'];
}
// set etc values
$this->_baseName = $conf['attributes']['key'];
$this->_name = $conf['attributes']['key'];
$this->_aggregate = isset($conf['attributes']['aggregate']) && $conf['attributes']['aggregate'] == '1';
$this->_aggregatePrefix = isset($conf['attributes']['aggregate-prefix']) ? $conf['attributes']['aggregate-prefix'] : NULL;
$this->_apiResource = $conf['attributes']['api-resource'];
$this->_cardinalityUnique = !$this->_cardinality || $this->isEntity() || (isset($conf['attributes']['cardinality-unique']) && $conf['attributes']['cardinality-unique'] == '0') ? FALSE : TRUE;
$this->_circularRef = isset($conf['attributes']['circular-ref']) && $conf['attributes']['circular-ref'] == '1';
$this->_skipPersistence = isset($conf['attributes']['skip-persistence']) && $conf['attributes']['skip-persistence'] == '1';
$this->_column = !$this->_skipPersistence ? (isset($conf['attributes']['column']) ? $conf['attributes']['column'] : $this->getDdlName(NULL, $this->_name, $entityGenerator->_ddlUpperCase, $entityGenerator->_columnPrefix, $entityGenerator->_columnPostfix, $this->_cardinality)) : NULL;
$this->_columnType = isset($conf['attributes']['column-type']) ? $conf['attributes']['column-type'] : NULL;
$this->_constraint = isset($conf['attributes']['constraint']) ? $conf['attributes']['constraint'] : NULL;
$this->_dateFormat = isset($conf['attributes']['date-format']) ? $conf['attributes']['date-format'] : NULL;
$this->_ddlCamelCase = $ddlCamelCase;
$this->_ddlUpperCase = isset($ddlUpperCase) ? $ddlUpperCase : NULL;
$this->_dtdCamelCase = $dtdCamelCase;
$this->_dtdName = isset($conf['attributes']['dtd-name']) ? $conf['attributes']['dtd-name'] : NULL;
$this->_default = isset($conf['attributes']['default']) ? $conf['attributes']['default'] : NULL;
$this->_hasDefault = isset($conf['attributes']['default']);
$this->_fileIconAttr = $this->_fileIconDir && $this->_isFile && isset($conf['attributes']['file-icon-attr']) ? $conf['attributes']['file-icon-attr'] : NULL;
$this->_fileIndexAttr = $this->_isFile && isset($conf['attributes']['file-index-attr']) ? $conf['attributes']['file-index-attr'] : NULL;
$this->_fileSizeAttr = $this->_isFile && isset($conf['attributes']['file-size-attr']) ? $conf['attributes']['file-size-attr'] : NULL;
$this->_fileUriAttr = $this->_isFile && isset($conf['attributes']['file-uri-attr']) ? $conf['attributes']['file-uri-attr'] : NULL;
$this->_fileUriKbAttr = $this->_isFile && isset($conf['attributes']['file-uri-kb-attr']) ? $conf['attributes']['file-uri-kb-attr'] : NULL;
$this->_fileUriMbAttr = $this->_isFile && isset($conf['attributes']['file-uri-mb-attr']) ? $conf['attributes']['file-uri-mb-attr'] : NULL;
$this->_fileProcessor = $this->_isFile && isset($conf['attributes']['file-processor']) ? $conf['attributes']['file-processor'] : NULL;
$this->_entityGenerator =& $entityGenerator;
$this->_indexed = isset($conf['attributes']['indexed']) && $conf['attributes']['indexed'] == '1';
$this->_jsonView = isset($conf['attributes']['json-view']) ? $conf['attributes']['json-view'] : NULL;
$this->_lazyLoad = isset($conf['attributes']['lazy-load']) && $conf['attributes']['lazy-load'] == '1';
$this->_lazyLoadExclusive = isset($conf['attributes']['lazy-load-exclusive']) && $conf['attributes']['lazy-load-exclusive'] == '1';
$this->_daoSuffix = $entityGenerator->_daoSuffix;
$this->_globalName = isset($conf['attributes']['global-name']) ? $conf['attributes']['global-name'] : (isset($conf['attributes']['is-global']) && $conf['attributes']['is-global'] == '1' ? $this->_name : NULL);
$this->_mapped = isset($conf['attributes']['mapped']) && $conf['attributes']['mapped'] == '1';
$this->_mappedExclude = isset($conf['attributes']['mapped-exclude']) ? explode(' ', $conf['attributes']['mapped-exclude']) : NULL;
$this->_mappedInclude = isset($conf['attributes']['mapped-include']) ? explode(' ', $conf['attributes']['mapped-include']) : NULL;
$this->_nullDbEmptyStr = (isset($conf['attributes']['null-db-empty-str']) && $conf['attributes']['null-db-empty-str'] == '1') || $entityGenerator->_nullDbEmptyStr;
$this->_voSuffix = $entityGenerator->_voSuffix;
$this->_orderBy = isset($conf['attributes']['order-by']) ? $conf['attributes']['order-by'] : NULL;
$this->_primaryKey = $entityGenerator->_primaryKey == $this->_name;
$this->_readOnly = isset($conf['attributes']['read-only']) && $conf['attributes']['read-only'] == '1';
$this->_recursiveLink = isset($conf['attributes']['recursive-link']) ? $conf['attributes']['recursive-link'] : NULL;
$this->_renderDisplOption = isset($conf['attributes']['render-displ-option']) && $conf['attributes']['render-displ-option'] == '1' ? TRUE : FALSE;
$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->_retrieveFunction = isset($conf['attributes']['retrieve-function']) ? $conf['attributes']['retrieve-function'] : NULL;
$this->_sequence = isset($conf['attributes']['sequence']) && $conf['attributes']['sequence'] == '1';
$this->_setConvert = isset($conf['attributes']['set-convert']) ? explode(' ', $conf['attributes']['set-convert']) : NULL;
$this->_setFunction = isset($conf['attributes']['set-function']) ? $conf['attributes']['set-function'] : NULL;
$this->_setOnly = isset($conf['attributes']['set-only']) && $conf['attributes']['set-only'] == '1';
$this->_skipWsdl = isset($conf['attributes']['skip-wsdl']) && $conf['attributes']['skip-wsdl'] == '1' ? TRUE : FALSE;
$this->_skipInclude = isset($conf['attributes']['skip-include']) && $conf['attributes']['skip-include'] == '1' ? TRUE : FALSE;
$this->_syncAttributes = isset($conf['attributes']['sync-attributes']) ? explode(' ', $conf['attributes']['sync-attributes']) : NULL;
$this->_table = isset($conf['attributes']['table']) ? $conf['attributes']['table'] : NULL;
if (isset($conf['attributes']['table-pk-column'])) {
$this->_tablePkColumn = $conf['attributes']['table-pk-column'];
}
if (isset($conf['thumbnail'])) {
$keys = array_keys($conf['thumbnail']);
foreach($keys as $key) {
if (!SRA_AttributeThumbnail::isValid($this->_thumbnails[$key] = new SRA_AttributeThumbnail($conf['thumbnail'][$key]))) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - thumbnail attribute $key is not valid for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
}
}
$this->_type = $this->_type;
if ($this->_sequence) {
$this->_type = SRA_DATA_TYPE_INT;
}
$this->_typeErrResource = isset($conf['attributes']['type-err-resource']) ? $conf['attributes']['type-err-resource'] : NULL;
$this->_unionLink = isset($conf['attributes']['union-link']) ? $conf['attributes']['union-link'] : NULL;
$this->_useReference = TRUE;
if (SRA_EntityModeler::isValidType($this->_type) && !$this->_isFile) {
if ($this->_attrMappings) {
$msg = "SRA_AttributeGenerator::SRA_AttributeGenerator: Failed - attr-mappings cannot be specified for non entity type attributes for attribute " . $conf['attributes']['key'];
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
$this->_useReference = FALSE;
}
// required bounds
if (is_array($this->_validators) && in_array(SRA_ATTRIBUTE_GENERATOR_REQUIRED, $this->_validators) && !$this->_cardinalityLower) {
$this->_cardinalityLower = 1;
}
$this->_onDeleteCascade = isset($conf['attributes']['on-delete-cascade']) && $conf['attributes']['on-delete-cascade'] == '1';
if (isset($conf['attributes']['on-delete-cascade'])) {
$this->_onDeleteCascadeSet = TRUE;
}
$this->_onRemoveDelete = isset($conf['attributes']['on-remove-delete']) && $conf['attributes']['on-remove-delete'] == '1';
$this->_xmlUseAttribute = !$this->_cardinality && !$this->isEntity() && isset($conf['attributes']['xml-use-attribute']) && $conf['attributes']['xml-use-attribute'] == '1';
$this->_xmlView = isset($conf['attributes']['xml-view']) ? $conf['attributes']['xml-view'] : NULL;
// check for attributes not allowed with ws-db
if ($entityGenerator->usesWsDb()) {
if ($this->_lazyLoadExclusive) $this->_lazyLoad = TRUE;
$err = NULL;
if ($this->_aggregate) $err = 'aggregate';
else if ($this->_aggregatePrefix) $err = 'aggregate-prefix';
else if (isset($conf['attributes']['column'])) $err = 'column';
else if (isset($conf['attributes']['column-type'])) $err = 'column-type';
else if ($this->_constraint) $err = 'constraint';
else if (isset($conf['attributes']['indexed'])) $err = 'indexed';
else if ($this->_mapped) $err = 'mapped';
else if ($this->_mappedExclude) $err = 'mapped-exclude';
else if ($this->_mappedInclude) $err = 'mapped-include';
else if ($this->_mappedPrefix) $err = 'mapped-prefix';
else if ($this->_mappedPostfix) $err = 'mapped-postfix';
else if ($this->_mappedResourcePrefix) $err = 'mapped-resource-prefix';
else if ($this->_mappedResourcePostfix) $err = 'mapped-resource-postfix';
else if ($this->_nullDbEmptyStr) $err = 'null-db-empty-str';
else if ($this->_onDeleteCascade) $err = 'on-delete-cascade';
else if ($this->_onRemoveDelete) $err = 'on-remove-delete';
else if ($this->_orderBy) $err = 'order-by';
else if ($this->_recursiveLink) $err = 'recursive-link';
else if ($this->_retrieveFunction) $err = 'retrieve-function';
else if ($this->_sequence) $err = 'sequence';
else if ($this->_setFunction) $err = 'set-function';
else if ($this->_table) $err = 'table';
else if ($this->_tablePkColumn) $err = 'table-pk-column';
else if ($this->_unionLink) $err = 'union-link';
if ($err) {
$msg = 'SRA_AttributeGenerator: Failed - the attribute ' . $err . ' cannot be used in conjunction with ws-db for entity ' . $entityGenerator->_name . ' and attribute ' . $this->_name;
$this->err = SRA_Error::logError($msg, __FILE__, __LINE__);
return;
}
}
}
// }}}
// public operations
// {{{ getAggregateAttributes
/**
* Returns all of the SRA_AttrMappings as SRA_AttributeGenerators for this attribute.
* @param boolean $addNamePrefix whether or not to prefix each mapping with this attribute's name followed by an underscore
* @access public
* @return SRA_AttributeGenerator[]
*/
function & getAggregateAttributes() {
if (!isset($this->_aggregateAttributes)) {
$this->_aggregateAttributes = array();
if ($this->isEntity() && $this->_aggregate) {
if (!($this->_aggregateAttributes =& $this->getMappedAttributes())) {
$this->_aggregateAttributes =& $this->_entityGenerators[$this->_type]->_attributeGenerators;
}
if ($this->_aggregatePrefix) {
$keys = array_keys($this->_aggregateAttributes);
foreach($keys as $key) {
$this->_aggregateAttributes[$key] = SRA_Util::copyObject($this->_aggregateAttributes[$key]);
if (!SRA_Util::beginsWith($this->_aggregateAttributes[$key]->_name, $this->_aggregatePrefix)) {
$this->_aggregateAttributes[$key]->_name = $this->_aggregatePrefix . strtoupper(substr($this->_aggregateAttributes[$key]->_name, 0, 1)) . substr($this->_aggregateAttributes[$key]->_name, 1);
}
}
}
}
}
return count($this->_aggregateAttributes) ? $this->_aggregateAttributes : NULL;
}
// }}}
// {{{ getConvertMethodName
/**
* Returns the name of this attribute formatted for a method (first letter is
* uppercase)
* @access public
* @return String
*/
function getConvertMethodName() {
return 'convert' . strtoupper(substr($this->_type, 0, 1)) . substr($this->_type, 1, strlen($this->_type) - 1);
}
// }}}
// {{{ getEntityPkColumn
/**
* if this attribute is an entity, returns the name of the primary key column
* for that entity
* @access public
* @return String
*/
function getEntityPkColumn() {
return $this->isEntity() && isset($this->_entityGenerators[$this->_type]) && ($pk =& $this->_entityGenerators[$this->_type]->getPrimaryKeyAttribute()) ? $pk->_column : 'unknown';
}
// }}}
// {{{ getEntityPkName
/**
* if this attribute is an entity, returns the name of the primary key
* attribute for that entity
* @access public
* @return String
*/
function getEntityPkName() {
return $this->isEntity() && isset($this->_entityGenerators[$this->_type]) && ($pk =& $this->_entityGenerators[$this->_type]->getPrimaryKeyAttribute()) ? $pk->_name : 'unknown';
}
// }}}
// {{{ getEntityTable
/**
* if this attribute is an entity, returns the name of the table for that entity
* @access public
* @return String
*/
function getEntityTable() {
return $this->isEntity() && isset($this->_entityGenerators[$this->_type]) ? $this->_entityGenerators[$this->_type]->_table : 'unknown';
}
// }}}
// {{{ getNestedElementDtdName
/**
* Returns the DTD name value for this attribute if it is used as a sub-element
* of the entity it belongs in
* @access public
* @return String
*/
function getNestedElementDtdName() {
$baseName = $this->_entityGenerator->_name . SRA_ATTRIBUTE_DTD_ATTR_PREFIX . strtoupper(substr($this->_name, 0, 1)) . substr($this->_name, 1);
return $this->_dtdName ? $this->_dtdName : ($this->_dtdCamelCase ? $baseName : SRA_Util::camelCaseToDashes($baseName));
}
// }}}
// {{{ getNestedElementDtdModfier
/**
* Returns the modifier for the nested dtd name
* @access public
* @return String
*/
function getNestedElementDtdModfier() {
return !$this->_isFile ? $this->getDtdModifier() : '?';
}
// }}}
// {{{ getSubElementDtdName
/**
* Returns the DTD name value for this attribute if it is used as a sub-element
* of the entity it belongs in
* @access public
* @return String
*/
function getSubElementDtdName() {
if ($this->_isFile) {
return $this->_dtdCamelCase ? SRA_ENTITY_MODELER_FILE_DTD_NAME : SRA_Util::camelCaseToDashes(SRA_ENTITY_MODELER_FILE_DTD_NAME);
}
else if ($this->isEntity()) {
return $this->getTypeDtdName();
}
}
// }}}
// {{{ getDtdModifier
/**
* Returns the modifier for the dtd sub-element dtd name
* @access public
* @return String
*/
function getDtdModifier() {
return $this->_cardinality ? '*' : '?';
}
// }}}
// {{{ getMappedAttributes
/**
* Returns all of the SRA_AttrMappings as SRA_AttributeGenerators for this attribute.
* @param boolean $addNamePrefix whether or not to prefix each mapping with this attribute's name followed by an underscore
* @access public
* @return SRA_AttributeGenerator[]
*/
function & getMappedAttributes($addNamePrefix = FALSE) {
$mappedAttrs = array();
// fully mapped
if ($this->_mapped) {
$keys = array_keys($this->_entityGenerators[$this->_type]->_attributeGenerators);
foreach ($keys as $key) {
// skip attribute
if (($this->_mappedExclude && in_array($key, $this->_mappedExclude)) || ($this->_mappedInclude && !in_array($key, $this->_mappedInclude))) { continue; }
$generator =& $this->_entityGenerators[$this->_type]->_attributeGenerators[$key];
// skip primary key attributes
if ($this->_entityGenerators[$this->_type]->_primaryKey && $generator->_name == $this->_entityGenerators[$this->_type]->_primaryKey) { continue; }
$col = $this->getDdlName($generator->_column, $generator->_name, $this->_entityGenerator->_ddlUpperCase, $this->_mappedPrefix, $this->_mappedPostfix);
$mapping = new SRA_AttrMapping($key, $col, $generator->_resource, $generator->_resourceHelp, $this->_mappedResourcePostfix, $this->_mappedResourcePrefix);
if (SRA_Error::isError($mappedAttrs[$key] =& $mapping->toAttributeGenerator($this, $this->_entityGenerators))) {
$msg = 'SRA_AttributeGenerator::getMappedAttributes: Unable to create AttributeMapping for mapped attribute ' . $this->_name . "::${key}";
return SRA_Error::logError($msg, __FILE__, __LINE__);
}
}
}
// partially mapped
else if ($this->_attrMappings) {
$keys = array_keys($this->_attrMappings);
foreach ($keys as $key) {
if (SRA_Error::isError($mappedAttrs[$key] =& $this->_attrMappings[$key]->toAttributeGenerator($this, $this->_entityGenerators))) {
$msg = "SRA_AttributeGenerator::getMappedAttributes: Unable to create AttributeMapping for mapped column ${key}";
return SRA_Error::logError($msg, __FILE__, __LINE__);
}
}
}
$keys = array_keys($mappedAttrs);
foreach ($keys as $key) {
if ($this->_table) {
$mappedAttrs[$key]->_table = $this->_table;
}
}
$keys = array_keys($mappedAttrs);
foreach ($keys as $key) {
while(SRA_Util::beginsWith($mappedAttrs[$key]->_name, $this->_name . '_')) {
$mappedAttrs[$key]->_name = substr($mappedAttrs[$key]->_name, strlen($this->_name) + 1);
}
if ($addNamePrefix && !SRA_Util::beginsWith($mappedAttrs[$key]->_name, $this->_name . '_')) {
$mappedAttrs[$key]->_name = $this->_name . '_' . $mappedAttrs[$key]->_name;
}
}
return count($mappedAttrs) ? $mappedAttrs : NULL;
}
// }}}
// {{{ getMethodName
/**
* Returns the name of this attribute formatted for a method (first letter is
* uppercase)
*
* @param string $attr optional - the name of the attribute to return the
* method name for
* @access public
* @return String
*/
function getMethodName($attr = FALSE, $base = FALSE) {
if (!$attr) {
$attr = $base ? $this->_baseName : $this->_name;
}
return strtoupper(substr($attr, 0, 1)) . substr($attr, 1, strlen($attr) - 1);
}
// }}}
// {{{ getNestedDAOName
/**
* Returns the name of the DAO for nested attributes
* @access public
* @return String
*/
function getNestedDAOName() {
return $this->_type . $this->_daoSuffix;
}
// }}}
// {{{ getNestedVOName
/**
* Returns the name of the VO for nested attributes
* @access public
* @return String
*/
function getNestedVOName() {
return $this->_type . $this->_voSuffix;
}
// }}}
// {{{ getOptionsMap
/**
* Returns the options map (value/label pairs) for this attribute. if this
* attribute is an entity, it will return TRUE if the an options map
* can/should be used for that type (only TRUE if 'displ' var specified)
*
* @access public
* @return array()
*/
function &getOptionsMap() {
static $map = array();
$mkey = $this->_entityGenerator->_name . '-' . $this->_name;
if (!isset($map[$mkey]) && (isset($this->_vars['options']) || isset($this->_vars['resources']) || isset($this->_vars['sql']) || isset($this->_vars['displ']))) {
$map[$mkey] = array();
// 'options' var
if (isset($this->_vars['options'])) {
$options = explode(' ', $this->_vars['options']);
$keys = array_keys($options);
foreach ($keys as $key) {
if (strstr($options[$key], '=')) {
$tmp = explode('=', $options[$key]);
$map[$mkey][trim($tmp[0])] = trim($tmp[1]);
}
else {
$map[$mkey][$options[$key]] = $options[$key];
}
}
}
// 'resources' var
else if (isset($this->_vars['resources'])) {
if (SRA_ResourceBundle::isValid($rb =& SRA_ResourceBundle::getBundle($this->_vars['resources']))) {
$map[$mkey] =& $rb->getData();
}
}
// 'sql' var
else if (isset($this->_vars['sql'])) {
$map[$mkey] =& SRA_AttributeValidator::getSqlOptionsMap($this->_vars['sql']);
}
// 'displ' var
else if (isset($this->_vars['displ'])) {
return TRUE;
}
}
if (isset($map[$mkey])) {
return $map[$mkey];
}
else {
return FALSE;
}
}
// }}}
// {{{ getOptionsValMethod
/**
* Returns the options map value method that should be used for entity type
* attributes with (option|options) validation constraints and a 'displ' var
* defined
*
* @access public
* @return string
*/
function getOptionsValMethod() {
return strstr($this->_vars['displ'], '$') ? 'parseString' : 'getAttribute';
}
// }}}
// {{{ getRangeArray
/**
* Returns the array of values possible for an attribute with a range
* constraint
* @access public
* @return String[]
*/
function getRangeArray() {
$values = array();
if (isset($this->_vars['min']) && isset($this->_vars['max'])) {
for ($i = $this->_vars['min']; $i<= $this->_vars['max']; $i++) {
$values[] = $i;
}
}
return $values;
}
// }}}
// {{{ getDtdSubElementName
/**
* Returns the DTD name value for an attribute declared as a sub-element
* @access public
* @return String
*/
function getDtdSubElementName() {
return $this->_entityGenerator->getDtdSubElementName($this->_name);
}
// }}}
// {{{ getVar
/**
* Returns the value of the var specified or FALSE if it doesn't exist
* @param string $id the id of the var to return
* @access public
* @return string
*/
function getVar($id) {
if (isset($this->_vars[$id])) {
return $this->_vars[$id];
}
return FALSE;
}
// }}}
// {{{ getWsdlType
/**
* returns the wsdl type for this attribute
* @access public
* @return string
*/
function getWsdlType() {
switch($this->_type) {
case SRA_DATA_TYPE_BLOB:
$type = $this->_isFile ? 'tns:SRA_File' : 'xsd:base64Binary';
break;
case SRA_DATA_TYPE_BOOLEAN:
$type = 'xsd:boolean';
break;
case SRA_DATA_TYPE_DATE:
$type = 'xsd:date';
break;
case SRA_DATA_TYPE_FLOAT:
$type = 'xsd:double';
break;
case SRA_DATA_TYPE_INT:
$type = 'xsd:integer';
break;
case SRA_DATA_TYPE_STRING:
$type = 'xsd:string';
break;
case SRA_DATA_TYPE_TIME:
$type = 'xsd:dateTime';
break;
default:
$type = 'tns:' . $this->_type;
break;
}
return $type;
}
// }}}
// {{{ hasOptions
/**
* Returns TRUE if this attribute has options
* @access public
* @return boolean
*/
function hasOptions() {
return isset($this->_vars['options']) || isset($this->_vars['resources']) || isset($this->_vars['sql']) || isset($this->_vars['displ']) || isset($this->_vars['code']);
}
// }}}
// {{{ hasCodeOptions
/**
* Returns TRUE if this attribute has code based options
* @access public
* @return boolean
*/
function hasCodeOptions() {
return isset($this->_vars['code']);
}
// }}}
// {{{ hasRbOptions
/**
* Returns TRUE if this attribute has SRA_ResourceBundle based options
* @access public
* @return boolean
*/
function hasRbOptions() {
return isset($this->_vars['resources']);
}
// }}}
// {{{ hasSqlOptions
/**
* Returns TRUE if this attribute has SQL based options
* @access public
* @return boolean
*/
function hasSqlOptions() {
return isset($this->_vars['sql']);
}
// }}}
// {{{ hasRange
/**
* Returns TRUE if this attribute has a range
* @access public
* @return boolean
*/
function hasRange() {
$keys = array_keys($this->_validators);
foreach ($keys as $key) {
if ($this->_validators[$key] == 'range') {
return TRUE;
}
}
return FALSE;
}
// }}}
// {{{ isBaseAttribute
/**
* Returns TRUE if this attribute is a base attribute that can be SET
* @access public
* @return boolean
*/
function isBaseAttribute() {
return ((!$this->_table || $this->_table == $this->_entityGenerator->_table) && !$this->_sequence && !$this->_readOnly && $this->_column);
}
// }}}
// {{{ isEntity
/**
* Returns TRUE if this attribute is actually a reference to another Entity
* entity
* @access public
* @return boolean
*/
function isEntity() {
return !SRA_EntityModeler::isValidType($this->_type);
}
// }}}
// {{{ isEntitySkipPersistence
/**
* returns TRUE if this is an entity attribute and the entity is corresponds
* to is non-persistent
* @access public
* @return boolean
*/
function isEntitySkipPersistence() {
return $this->isEntity() && isset($this->_entityGenerators[$this->_type]) && $this->_entityGenerators[$this->_type]->_skipPersistence;
}
// }}}
// {{{ isEntitySkipPersistenceNoPk
/**
* returns TRUE if this is an entity attribute and the entity is corresponds
* to is non-persistent and does not have a primary key attribute
* @access public
* @return boolean
*/
function isEntitySkipPersistenceNoPk() {
return $this->isEntitySkipPersistence() && !$this->_entityGenerators[$this->_type]->_primaryKey;
}
// }}}
// {{{ isRequired
/**
* Returns TRUE if this attribute is required (based on whether or not it
* has the 'required' validator)
* @access public
* @return boolean
*/
function isRequired() {
$keys = array_keys($this->_validators);
foreach ($keys as $key) {
if ($this->_validators[$key] == 'required') {
return TRUE;
}
}
return FALSE;
}
// }}}
// {{{ _mergeDefaultViews
/**
* creates views based on the global-views/default-view configuration for the
* model
* @access private
* @return void
*/
function _mergeDefaultViews(& $conf, & $defaultViews, $type, $attrName, $entityName, $cardinality, $depends) {
if ($defaultViews) {
$depends = $depends ? explode(' ', $depends) : NULL;
$keys = array_keys($defaultViews);
foreach($keys as $key) {
if ((!in_array('*', $defaultViews[$key]['types']) && !in_array($type, $defaultViews[$key]['types'])) ||
($defaultViews[$key]['includeAttrs'] && !in_array($attrName, $defaultViews[$key]['includeAttrs'])) ||
($defaultViews[$key]['excludeAttrs'] && in_array($attrName, $defaultViews[$key]['excludeAttrs'])) ||
($defaultViews[$key]['includeEntities'] && !in_array($entityName, $defaultViews[$key]['includeEntities'])) ||
($defaultViews[$key]['excludeEntities'] && in_array($entityName, $defaultViews[$key]['excludeEntities'])) ||
(isset($defaultViews[$key]['cardinality']) && $defaultViews[$key]['cardinality'] != $cardinality) ||
(!isset($defaultViews[$key]['cardinality']) && $cardinality) ||
($defaultViews[$key]['includeDepends'] && (!$depends || count(array_intersect($depends, $defaultViews[$key]['includeDepends'])) != count($defaultViews[$key]['includeDepends']))) ||
($defaultViews[$key]['excludeDepends'] && $depends && count(array_intersect($depends, $defaultViews[$key]['excludeDepends'])) > 0)) { continue; }
if (!$conf['view']) { $conf['view'] = array(); }
if (!isset($conf['view'][$defaultViews[$key]['id']])) {
$conf['view'][$defaultViews[$key]['id']] = array('attributes' => array('key' => $defaultViews[$key]['id'], 'extends' => $defaultViews[$key]['view']));
}
}
}
}
// }}}
// static methods
// {{{ 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_attributegenerator');
}
// }}}
// private operations
}
// }}}
?>