CC-2166: Packaging Improvements. Moved the Zend app into airtime_mvc. It is now installed to /var/www/airtime. Storage is now set to /srv/airtime/stor. Utils are now installed to /usr/lib/airtime/utils/. Added install/airtime-dircheck.php as a simple test to see if everything is install/uninstalled correctly.

This commit is contained in:
Paul Baranowski 2011-04-14 18:55:04 -04:00
parent 514777e8d2
commit b11cbd8159
4546 changed files with 138 additions and 51 deletions

View file

@ -0,0 +1,70 @@
#!/bin/sh
# Shell wrapper for Propel generator
# $Id$
#
# This script will do the following:
# - check for PHING_COMMAND env, if found, use it.
# - if not found assume php is on the path
# - check for PROPEL_GEN_HOME env, if found use it
# - if not look for it
if [ -z "$PROPEL_GEN_HOME" ] ; then
# try to find Propel
if [ -d /opt/propel/generator ] ; then
PROPEL_GEN_HOME=/opt/propel/generator
fi
if [ -d "${HOME}/opt/propel/generator" ] ; then
PROPEL_GEN_HOME="${HOME}/opt/propel/generator"
fi
if [ -d "/usr/local/propel/generator" ] ; then
PROPEL_GEN_HOME="/usr/local/propel/generator"
fi
if [ -d "${HOME}/usr/propel/generator" ] ; then
PROPEL_GEN_HOME="${HOME}/usr/propel/generator"
fi
## resolve links - the script name may be a link to phing's home
PRG="$0"
progname=`basename "$0"`
saveddir=`pwd`
# need this for relative symlinks
dirname_prg=`dirname "$PRG"`
cd "$dirname_prg"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
cd "$saveddir"
PROPEL_GEN_HOME=`dirname "$PRG"`/..
# make it fully qualified
PROPEL_GEN_HOME=`cd "$PROPEL_GEN_HOME" && pwd`
# make it available in PHP via getenv("PROPEL_GEN_HOME")
export PROPEL_GEN_HOME
fi
if [ -z "$PHING_COMMAND" ] ; then
# echo "WARNING: PHING_COMMAND environment not set. (Assuming phing on PATH)"
export PHING_COMMAND="phing"
fi
if [ $# = 1 ] ; then
$PHING_COMMAND -f $PROPEL_GEN_HOME/build.xml -Dusing.propel-gen=true -Dproject.dir=$saveddir $*
else
$PHING_COMMAND -f $PROPEL_GEN_HOME/build.xml -Dusing.propel-gen=true -Dproject.dir=$*
fi

View file

@ -0,0 +1,32 @@
@echo off
rem *********************************************************************
rem ** The Propel generator convenience script for Windows based systems
rem ** $Id$
rem *********************************************************************
rem This script will do the following:
rem - check for PHING_COMMAND env, if found, use it.
rem - if not found detect php, if found use it, otherwise err and terminate
rem - check for PROPEL_GEN_HOME env, if found use it
rem - if not found error and leave
if "%OS%"=="Windows_NT" @setlocal
rem %~dp0 is expanded pathname of the current script under NT
set DEFAULT_PROPEL_GEN_HOME=%~dp0..
if "%PROPEL_GEN_HOME%" == "" set PROPEL_GEN_HOME=%DEFAULT_PROPEL_GEN_HOME%
set DEFAULT_PROPEL_GEN_HOME=
if "%PHING_COMMAND%" == "" set PHING_COMMAND=phing.bat
set nbArgs=0
for %%x in (%*) do Set /A nbArgs+=1
if %nbArgs% leq 1 (
%PHING_COMMAND% -f "%PROPEL_GEN_HOME%\build.xml" -Dusing.propel-gen=true -Dproject.dir="%CD%" %*
) else (
%PHING_COMMAND% -f "%PROPEL_GEN_HOME%\build.xml" -Dusing.propel-gen=true -Dproject.dir=%*
)
if "%OS%"=="Windows_NT" @endlocal

View file

@ -0,0 +1,513 @@
<project name="propel" default="main">
<!--
Note - You should not have to edit this file.
Instead, if calling build-propel.xml directly, edit the build.properties
that is in the same directory. If calling build-propel.xml via another
build file, you can also use the build.properties in the same directory,
or set the property propel.contextProperties to the file
to use in place of build.properties (e.g. project.properties).
-->
<property name="build.properties" value="build.properties"/>
<property name="propel.contextProperties" value="./${build.properties}"/>
<property name="propel.home" value="."/>
<available file="${propel.home}/build.properties" property="globalBuildPopertiesExists"/>
<if>
<and>
<isset property="globalBuildPopertiesExists"/>
</and>
<then>
<property file="${propel.home}/build.properties"/>
</then>
</if>
<!--
The default.properties file will map old properties to the new ones along
with setting the corret defaults.
-->
<property file="${propel.home}/default.properties"/>
<!--
Do forward declarations of all of our tasks to
centralize them and clean up the targets.
-->
<path id="propelclasses">
<pathelement dir="${propel.home}/lib/"/>
<pathelement dir="${propel.project.dir}/"/>
</path>
<taskdef
name="propel-data-model"
classname="task.PropelDataModelTemplateTask" classpathRef="propelclasses"/>
<taskdef
name="propel-om"
classname="task.PropelOMTask" classpathRef="propelclasses"/>
<taskdef
name="propel-data-dtd"
classname="task.PropelDataDTDTask" classpathRef="propelclasses"/>
<taskdef
name="propel-data-dump"
classname="task.PropelDataDumpTask" classpathRef="propelclasses"/>
<taskdef
name="propel-data-sql"
classname="task.PropelDataSQLTask" classpathRef="propelclasses"/>
<taskdef
name="propel-schema-reverse"
classname="task.PropelSchemaReverseTask" classpathRef="propelclasses"/>
<taskdef
name="propel-sql"
classname="task.PropelSQLTask" classpathRef="propelclasses"/>
<taskdef
name="propel-sql-exec"
classname="task.PropelSQLExec" classpathRef="propelclasses"/>
<taskdef
name="propel-graphviz"
classname="task.PropelGraphvizTask" classpathRef="propelclasses"/>
<taskdef
name="propel-convert-conf"
classname="task.PropelConvertConfTask" classpathRef="propelclasses"/>
<!-- ================================================================ -->
<!-- M A I N T A R G E T -->
<!-- ================================================================ -->
<!-- This default target will run all the targets that generate -->
<!-- source. You will probably only run this target once then -->
<!-- call individual targets as necessary to update your sources -->
<!-- when you change your XML schema. -->
<!-- ================================================================ -->
<target
name="main"
depends="mysqli-check"
description="==> generates sql + om classes">
<phingcall target="sql"/>
<phingcall target="om"/>
<phingcall target="convert-conf"/>
</target>
<!-- ================================================================ -->
<!-- C H E C K R U N O N L Y O N S C H E M A C H A N G E -->
<!-- ================================================================ -->
<!-- Maps the propel.runOnlyOnSchemaChange to -->
<!-- propel.internal.runOnlyOnSchemaChange -->
<!-- ================================================================ -->
<target name="check-run-only-on-schema-change">
<condition property="propel.internal.runOnlyOnSchemaChange">
<equals arg1="${propel.runOnlyOnSchemaChange}" arg2="true"/>
</condition>
</target>
<!-- ================================================================ -->
<!-- G E N E R A T E P R O J E C T S Q L -->
<!-- ================================================================ -->
<!-- Generate the SQL for your project, These are in addition -->
<!-- to the base Turbine tables! The tables you require for your -->
<!-- project should be specified in project-schema.xml. -->
<!-- ================================================================ -->
<target
name="sql-check"
depends="check-run-only-on-schema-change"
if="propel.internal.runOnlyOnSchemaChange">
<uptodate
property="propel.internal.sql.uptodate"
targetfile="${propel.sql.dir}/${propel.schema.default.basename}.sql">
<srcfiles dir="${propel.schema.dir}" includes="**/${propel.schema.default.basename}.xml" />
</uptodate>
</target>
<!-- temporary target to check whether postgres is being used with identifier quoting ON.
If so, a warning is issued, since identifier quoting is only paritally implemented & this point. -->
<target name="pgsql-quoting-check">
<if>
<and>
<equals arg1="${propel.database}" arg2="pgsql"/>
<equals arg1="${propel.disableIdentifierQuoting}" arg2=""/>
</and>
<then>
<warn>ATTENTION: It appears you are using PostgreSQL and you have identifier-quoting turned on.</warn>
<warn>It is suggested that you disable identifier quoting when using PostgreSQL -- especially if you</warn>
<warn>have case-sensitive columns in your database.</warn>
<warn></warn>
<warn>To disable identifier quoting, add the following property to your build.properties (or specify</warn>
<warn>it using -D on commandline):</warn>
<warn></warn>
<warn>propel.disableIdentifierQuoting=true</warn>
<warn></warn>
<warn>You can ignore this warning if you understand the issues related to case-sensitivity and Propel's</warn>
<warn>DDL-only implementation of identifier quoting.</warn>
</then>
</if>
</target>
<!-- temporary target to check whether mysqli is being used
If so, a warning is issued, since this is deprecated -->
<target name="mysqli-check">
<if>
<and>
<equals arg1="${propel.database}" arg2="mysqli"/>
</and>
<then>
<warn>ATTENTION: It appears you are using the mysqli driver.</warn>
<warn></warn>
<warn>This driver is no longer supported by Propel because Propel now uses PDO for database connections.</warn>
<warn>Please use mysqli driver instead.</warn>
<fail>Use 'mysql' instead of 'mysqli' for your propel.database property.</fail>
</then>
</if>
</target>
<target
name="sql"
depends="sql-check,pgsql-quoting-check,mysqli-check"
unless="propel.internal.sql.uptodate"
description="==> generates the SQL for your project">
<echo message="+------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Generating SQL for YOUR Propel project! |"/>
<echo message="| |"/>
<echo message="+------------------------------------------+"/>
<phingcall target="sql-template"/>
</target>
<target name="sql-template">
<propel-sql
validate="${propel.schema.validate}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
outputDirectory="${propel.sql.dir}"
sqldbmap="${propel.sql.dir}/sqldb.map"
targetDatabase="${propel.database}"
packageObjectModel="${propel.packageObjectModel}"
url="${propel.database.url}"
userId="${propel.database.user}"
password="${propel.database.password}">
<mapper type="glob" from="${propel.sql.mapper.from}" to="${propel.sql.mapper.to}"/>
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.sql.includes}"
excludes="${propel.schema.sql.excludes}"
/>
</propel-sql>
</target>
<!-- ================================================================ -->
<!-- C R E A T E T A R G E T D A T A B A S E -->
<!-- ================================================================ -->
<!-- Create the target database by executing a generated script -->
<!-- that is capable of performing the task. -->
<!-- ================================================================ -->
<target name="create-db-check">
<condition property="propel.internal.manualCreation">
<equals arg1="${propel.database.manualCreation}" arg2="true"/>
</condition>
</target>
<target
name="create-db"
unless="propel.internal.manualCreation"
depends="create-db-check,mysqli-check"
description="==> generates the target database">
<fail message="create-db target temporarily disabled, while we replace creole components."/>
<!--
<propel-data-model
validate="${propel.schema.validate}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
controlTemplate="${propel.template.sqlDbInit}"
outputDirectory="${propel.sql.dir}"
outputFile="create-db.sql"
targetDatabase="${propel.database}"
dbEncoding="${propel.database.encoding}"
templatePath="${propel.templatePath}"
packageObjectModel="${propel.packageObjectModel}">
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.create-db.includes}"
excludes="${propel.schema.create-db.excludes}"
/>
</propel-data-model>
<echo message="Executing the create-db.sql script ..."/>
<sql
autocommit="true"
driver="${propel.database.driver}"
onerror="continue"
src="${propel.sql.dir}/create-db.sql"
url="${propel.database.createUrl}"
/>
-->
</target>
<!-- ================================================================ -->
<!-- I N S E R T S I N G L E S Q L F I L E S -->
<!-- ================================================================ -->
<target
name="insert-sql"
description="==> inserts the generated sql ">
<propel-sql-exec
autocommit="true"
onerror="continue"
sqldbmap="${propel.sql.dir}/sqldb.map"
srcDir="${propel.sql.dir}"
url="${propel.database.buildUrl}"
userId="${propel.database.user}"
password="${propel.database.password}"
/>
</target>
<!-- ================================================================ -->
<!-- N E W R E V E R S E T O X M L -->
<!-- ================================================================ -->
<target
name="reverse"
description="==> generate xml schema from reverse-engineered database (new)">
<echo message="+-----------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Generating XML from PDO connection ! |"/>
<echo message="| |"/>
<echo message="+-----------------------------------------------+"/>
<propel-schema-reverse
databaseName="${propel.project}"
dbSchema="${propel.database.schema}"
dbEncoding="${propel.database.encoding}"
url="${propel.database.buildUrl}"
userId="${propel.database.user}"
password="${propel.database.password}"
outputFile="${propel.schema.dir}/${propel.default.schema.basename}.xml"
samePhpName="${propel.samePhpName}"
addVendorInfo="${propel.addVendorInfo}"
addValidators="${propel.addValidators}"
/>
</target>
<!-- ================================================================ -->
<!-- Generate SQL from XML data file -->
<!-- ================================================================ -->
<target
name="datasql"
description="==> generates sql from data xml">
<echo message="+-----------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Generating SQL from data XML ! |"/>
<echo message="| |"/>
<echo message="+-----------------------------------------------+"/>
<propel-data-sql
validate="${propel.schema.validate}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
outputDirectory="${propel.sql.dir}"
sqldbmap="${propel.sql.dir}/sqldb.map"
dbEncoding="${propel.database.encoding}"
targetDatabase="${propel.database}"
datadbmap="${propel.schema.dir}/datadb.map"
srcDir="${propel.schema.dir}">
<mapper type="glob" from="${propel.datasql.mapper.from}" to="${propel.datasql.mapper.to}"/>
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.datadtd.includes}"
excludes="${propel.schema.datadtd.excludes}"
/>
</propel-data-sql>
</target>
<!-- ================================================================ -->
<!-- Dump data from database into xml file -->
<!-- ================================================================ -->
<target
name="datadump"
description="==> dump data from database into xml file">
<echo message="+-----------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Dumping the data from database into XML |"/>
<echo message="| |"/>
<echo message="+-----------------------------------------------+"/>
<propel-data-dump
validate="${propel.schema.validate}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
targetDatabase="${propel.database}"
datadbmap="${propel.schema.dir}/datadb.map"
databaseDriver="${propel.database.driver}"
dbEncoding="${propel.database.encoding}"
databaseUrl="${propel.database.url}"
databaseUser="${propel.database.user}"
databasePassword="${propel.database.password}"
outputDirectory="${propel.schema.dir}">
<mapper type="glob" from="${propel.datadump.mapper.from}" to="${propel.datadump.mapper.to}"/>
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.datadtd.includes}"
excludes="${propel.schema.datadtd.excludes}"
/>
</propel-data-dump>
</target>
<!-- ================================================================ -->
<!-- G E N E R A T E P R O J E C T D A T A D T D -->
<!-- ================================================================ -->
<!-- Generate the DATA DTD for your project -->
<!-- ================================================================ -->
<target
name="datadtd"
description="==> generates the DATA DTD for your project">
<echo message="+-----------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Generating Data DTD for YOUR Propel project! |"/>
<echo message="| |"/>
<echo message="+-----------------------------------------------+"/>
<propel-data-dtd
validate="${propel.schema.validate}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
targetDatabase="${propel.database}"
outputDirectory="${propel.output.dir}"
templatePath="${propel.templatePath}">
<!-- TODO: add properties for the mapper type, from, and to -->
<mapper type="glob" from="${propel.datadtd.mapper.from}" to="${propel.datadtd.mapper.to}"/>
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.datadtd.includes}"
excludes="${propel.schema.datadtd.excludes}"
/>
</propel-data-dtd>
</target>
<!-- ================================================================ -->
<!-- G E N E R A T E P R O J E C T P E E R B A S E D O M -->
<!-- ================================================================ -->
<!-- Generate the Peer-based object model for your project. -->
<!-- These are in addition to the base Propel OM! -->
<!-- ================================================================ -->
<target
name="om-check"
depends="check-run-only-on-schema-change"
if="propel.internal.runOnlyOnSchemaChange">
<uptodate
property="propel.internal.om.uptodate"
targetfile="${propel.php.dir}/report.${propel.project}.om.generation">
<srcfiles dir="${propel.schema.dir}" includes="**/${propel.schema.om.includes}.xml" />
</uptodate>
</target>
<target
name="om"
depends="om-check,mysqli-check"
unless="propel.internal.om.uptodate"
description="==> generates the Peer-based object model for your project">
<echo message="+------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Generating Peer-based Object Model for |"/>
<echo message="| YOUR Propel project! |"/>
<echo message="| |"/>
<echo message="+------------------------------------------+"/>
<phingcall target="om-template"/>
<!--<phingcall target="om-tar"/>-->
</target>
<target name="om-template">
<propel-om
validate="${propel.schema.validate}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
outputDirectory="${propel.php.dir}"
targetDatabase="${propel.database}"
targetPackage="${propel.targetPackage}"
targetPlatform="${propel.targetPlatform}"
packageObjectModel="${propel.packageObjectModel}">
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.om.includes}"
excludes="${propel.schema.om.excludes}"
/>
</propel-om>
</target>
<!-- ================================================================== -->
<!-- X M L R U N T I M E C O N F T O P H P A R R A Y -->
<!-- ================================================================== -->
<target
name="convert-conf"
description="==> converts properties file to PHP array">
<echo message="+------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Converting runtime config file to an |"/>
<echo message="| array dump for improved performance. |"/>
<echo message="| |"/>
<echo message="+------------------------------------------+"/>
<echo>Output file: ${propel.runtime.phpconf.file}</echo>
<echo>XMLFile: ${propel.conf.dir}/${propel.runtime.conf.file}</echo>
<propel-convert-conf
targetDatabase="${propel.database}"
xsd="${propel.schema.xsd.file}"
xsl="${propel.schema.xsl.file}"
xmlConfFile="${propel.conf.dir}/${propel.runtime.conf.file}"
outputDirectory="${propel.phpconf.dir}"
outputFile="${propel.runtime.phpconf.file}"
packageObjectModel="${propel.packageObjectModel}">
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.sql.includes}"
excludes="${propel.schema.sql.excludes}"
/>
</propel-convert-conf>
</target>
<target
name="graphviz"
depends="sql-check"
description="==> generates Graphviz file for your project">
<echo message="+------------------------------------------+"/>
<echo message="| |"/>
<echo message="| Generating Graphiz for YOUR Propel |"/>
<echo message="| project! |"/>
<echo message="| |"/>
<echo message="+------------------------------------------+"/>
<propel-graphviz
outputDirectory="${propel.graph.dir}"
targetDatabase="${propel.database}"
sqldbmap="${propel.sql.dir}/sqldb.map"
packageObjectModel="${propel.packageObjectModel}">
<mapper type="glob" from="${propel.sql.mapper.from}" to="${propel.sql.mapper.to}"/>
<schemafileset dir="${propel.schema.dir}"
includes="${propel.schema.sql.includes}"
excludes="${propel.schema.sql.excludes}"
/>
</propel-graphviz>
</target>
</project>

View file

@ -0,0 +1,192 @@
# -------------------------------------------------------------------
#
# P R O P E L C O N F I G U R A T I O N F I L E
#
# -------------------------------------------------------------------
# This file contains some example properties. Ideally properties
# should be specified in the project-specific build.properties file;
# however, this file can be used to specify non-default properties
# that you would like to use accross all of your Propel projects.
# -------------------------------------------------------------------
#
propel.home = .
# -------------------------------------------------------------------
#
# P R O J E C T
#
# -------------------------------------------------------------------
# This is the name of your Propel project. The name of your Propel
# project is used (by default) to determine where the generator will
# find needed configuration files and will place resuilting build
# files. E.g. if your project is named 'killerapp', Propel will
# look here for schema.xml and runtime-conf.xml files:
#
# projects/killerapp/
#
# -------------------------------------------------------------------
# You can set this here, but it's preferrable to set this in a
# project-specific build.properties file.
#
# propel.project = bookstore
# -------------------------------------------------------------------
#
# T A R G E T D A T A B A S E
#
# -------------------------------------------------------------------
# This is the target database, only considered when generating
# the SQL for your Propel project. Your possible choices are:
#
# mssql, mysql, oracle, pgsql, sqlite
# -------------------------------------------------------------------
# You can set this here, but it's preferrable to set this in a
# project-specific build.properties file.
#
# propel.database = mysql
# -------------------------------------------------------------------
#
# O B J E C T M O D E L I N F O R M A T I O N
#
# -------------------------------------------------------------------
# These settings will allow you to customize the way your
# Peer-based object model is created.
# -------------------------------------------------------------------
# addGenericAccessors
# If true, Propel adds methods to get database fields by name/position.
#
# addGenericMutators
# If true, Propel adds methods to set database fields by name/position.
#
# addSaveMethod
# If true, Propel adds tracking code to determine how to save objects.
#
# addTimeStamp
# If true, Propel true puts time stamps in phpdoc of generated om files.
#
# basePrefix
# A string to pre-pend to the file names of base data and peer objects.
#
# complexObjectModel
# If true, Propel generates data objects with collection support and
# methods to easily retreive foreign key relationships.
#
# targetPackage
# Sets the PHP "package" the om files will generated to, e.g.
# "com.company.project.om".
#
# targetPlatform
# Sets whether Propel is building classes for php5 (default)
# or php4 (experimental).
#
# packageObjectModel
# Sets whether Propel is packaging ObjectModel fro several
# [package].schema.xml files. The <database package="packageName">
# attribute has to be set then. (warning: this is experimental!)
#
# -------------------------------------------------------------------
# classes will be put in (and included from) this directory
# e.g. if package is "bookstore" then om will expect include('bookstore/Book.php'); to work.
# use dot-path notation -- e.g. my.bookstore -> my/bookstore.
#
propel.targetPackage = ${propel.project}
propel.addGenericAccessors = false
propel.addGenericMutators = false
propel.addSaveMethod = true
propel.addTimeStamp = true
propel.basePrefix = Base
propel.complexObjectModel = true
propel.targetPlatform = php5
propel.packageObjectModel = false
# -------------------------------------------------------------------
#
# D B C O N N E C T I O N S E T T I N G S
#
# -------------------------------------------------------------------
# PDO connection settings. These connection settings are used by
# build tagets that perform database operations (e.g. 'insert-sql',
# 'reverse').
#
# You can set them here, but it's preferrable to set these properties
# in a project-specific build.properties file.
#
# If you want to use a custom driver, specify it below, otherwise
# leave it blank or comment it out to use Creole stock driver.
#
# propel.database.driver = creole.drivers.sqlite.SQLiteConnection
# Note that if you do not wish to specify the database (e.g. if you
# are using multiple databses) you can use the @DB@ token which
# will be replaced with a database at runtime.
#
# propel.database.url = mysql:host=$host;dbname=$database
# For MySQL or Oracle, you also need to specify username & password
# propel.database.user = [db username]
# propel.database.password = [db password]
# Use the URL below to specify a DSN to used to create the database.
# Note that this URL should not contain the database name, as you will
# get an error if the database does not exist.
# (This does not apply to SQLite since the databse is automatically created
# when the connection is made -- if it does not already exist.)
#
# propel.database.createUrl = mysql:host=$host;dbname=$database
# -------------------------------------------------------------------
#
# D A T A B A S E TO X M L
#
# -------------------------------------------------------------------
#
# samePhpName
# If true, the reverse task will set the phpName attribute for the
# tables and columns to be the same as SQL name.
#
# addVendorInfo
# If true, the reverse task will add vendor specific information
# to the database schema
#
# addValidators
# Bitfield like option to turn on/off addition of Validator and
# Rule tags to the schema. Uses a boolean syntax like in php.ini.
# Allowed tokens are:
# none add no validators)
# all add all validators)
# maxlength add maxlengths for string type columns)
# maxvalue add maxvalue for numeric columns)
# type add notmatch validators for numeric columns)
# required add required validators for required columns)
# unique add unique validators for unique indexes)
# Allowed operators are:
# & bitwise AND
# | bitwise OR
# ~ bitwise NOT
#
# -------------------------------------------------------------------
# propel.samePhpName = false
# propel.addVendorInfo=true
# propel.addValidators=none
# -------------------------------------------------------------------
#
# D A T A B A S E B U I L D C O N F I G
#
# -------------------------------------------------------------------
# Some databases provide some configuration options that can be set
# in this script.
#
# === MySQL
# propel.mysql.tableType
# Use this property to set the table type of generated tables (e.g. InnoDB, MyISAM).

View file

@ -0,0 +1,184 @@
<!--
Use this file to faciliate easy per-project building.
Simply create a build.properties file in your project directory,
for example ./projects/bookstore/build.properties, that contains
any needed (i.e. to override) values for that project.
Call this build script and specify the name of the project and
(optionally) the name of the target you wish to execute (default is
'main' target) of build-propel.xml.
Normal use:
$> phing -Dproject=bookstore
Specific target:
$> phing -Dproject=bookstore -Dtarget=insert-sql
-->
<project name="propel-project-builder" default="main">
<!-- in case ${project.dir} was specified on command line, we set the project.dir
property here. If it wasn't set, then this will be bogus, but it will
be overridden by the "set-project-dir" target. -->
<resolvepath propertyName="propel.project.dir" file="${project.dir}" dir="${application.startdir}"/>
<!-- set a default target if none provided -->
<property name="target" value="main"/>
<!-- Set a default name for the build.properties file.
This allows for overriding the name of the build.properties file; however,
Propel still expects to find the file in the ${propel.project.dir}.
-->
<property name="build.properties" value="build.properties"/>
<target name="check-buildprops-exists">
<available file="${propel.project.dir}/${build.properties}" property="projBuildPopertiesExists"/>
</target>
<target name="check-buildprops" unless="projBuildPopertiesExists" depends="check-buildprops-exists">
<echo message="====================================================="/>
<echo message="Could not open ${build.properties} file:"/>
<echo message=" ${propel.project.dir}/${build.properties}"/>
<echo message=" "/>
<echo message="Make sure that '${propel.project.dir}' is a valid path"/>
<echo message="and that it contains a ${build.properties} file."/>
<echo message="====================================================="/>
<fail message="Missing configuration file (see description above)."/>
</target>
<target name="check-project-or-dir-set">
<condition property="projectOrDirSet">
<or>
<isset property="project"/>
<isset property="project.dir"/>
</or>
</condition>
</target>
<target name="check-buildprops-for-propel-gen" if="using.propel-gen" unless="projBuildPopertiesExists" depends="check-buildprops-exists">
<echo message="=========================================================="/>
<echo message="Could not open ${build.properties} file:"/>
<echo message=" ${propel.project.dir}/${build.properties}"/>
<echo message=" "/>
<echo message="Project directory not specified or invalid. You must "/>
<echo message="specify the path to your project directory and your "/>
<echo message="project directory must contain your ${build.properties} "/>
<echo message="and schema.xml files. "/>
<echo message=" "/>
<echo message="Usage: "/>
<echo message=" "/>
<echo message="$&gt; propel-gen /path/to/projectdir [target]"/>
<echo message=" "/>
<echo message="=========================================================="/>
<fail message="No project directory specified."/>
</target>
<target name="check-project-set" unless="projectOrDirSet" depends="check-project-or-dir-set">
<echo message="====================================================="/>
<echo message="Project not specified. You must enter a project name. "/>
<echo message="In the future you can enter it on the command line: "/>
<echo message=" "/>
<echo message="-Dproject=bookstore"/>
<echo message=" "/>
<echo message="This will attempt to find your project directory in"/>
<echo message="the default directory (./projects/bookstore)."/>
<echo message=" "/>
<echo message="You can also avoid this message and specicfy a custom "/>
<echo message="directory, using the project.dir property:"/>
<echo message=" "/>
<echo message="-Dproject.dir=/path/to/bookstore"/>
<echo message="====================================================="/>
<input propertyname="project" promptChar=":">Project name</input>
<property name="propel.project" value="${project}" override="true"/>
</target>
<target name="set-project-dir" unless="project.dir" depends="check-project-set">
<echo>No project.dir was specified, using default path: ./projects/${project}</echo>
<property name="propel.project.dir" value="./projects/${project}" override="true"/>
</target>
<target name="configure" depends="set-project-dir,check-buildprops-for-propel-gen,check-buildprops">
<if>
<isset property="additional.properties"/>
<then>
<echo>Processing additional properties file: ${additional.properties}</echo>
<resolvepath propertyName="additional.properties.resolved" file="${additional.properties}" dir="${application.startdir}"/>
<property file="${additional.properties.resolved}"/>
</then>
</if>
<echo msg="Loading project-specific props from ${propel.project.dir}/${build.properties}"/>
<property file="${propel.project.dir}/${build.properties}"/>
</target>
<target name="main" depends="configure" description="The main target. Includes project-specific build.properties and calls the build-propel.xml script">
<phing phingfile="./build-propel.xml" target="${target}"/>
</target>
<!--
Convenience mappings to build-propel.xml main targets
This makes it possible to use this buildfile w/o needing to specify
target as a property, e.g.:
$> phing -Dproject=bookstore insert-sql
The main reason for this is just consistency w/ old build-propel.xml file
(primarily for documentation & user confusion avoidance reasons). There are relatively
few & infrequently changing main targets of build-propel.xml, so it's a non-
issue as far as maintenance is concerned.
-->
<target name="convert-conf" depends="configure">
<phing phingfile="build-propel.xml" target="convert-conf"/>
</target>
<target name="create-db" depends="configure">
<phing phingfile="build-propel.xml" target="create-db"/>
</target>
<target name="reverse" depends="configure">
<phing phingfile="build-propel.xml" target="reverse"/>
</target>
<target name="datadtd" depends="configure">
<phing phingfile="build-propel.xml" target="datadtd"/>
</target>
<target name="datadump" depends="configure">
<phing phingfile="build-propel.xml" target="datadump"/>
</target>
<target name="datasql" depends="configure">
<phing phingfile="build-propel.xml" target="datasql"/>
</target>
<target name="insert-sql" depends="configure">
<phing phingfile="build-propel.xml" target="insert-sql"/>
</target>
<target name="om" depends="configure">
<phing phingfile="build-propel.xml" target="om"/>
</target>
<target name="new-om" depends="configure">
<phing phingfile="build-propel.xml" target="new-om"/>
</target>
<target name="sql" depends="configure">
<phing phingfile="build-propel.xml" target="sql"/>
</target>
<target name="old-sql" depends="configure">
<phing phingfile="build-propel.xml" target="old-sql"/>
</target>
<target name="graphviz" depends="configure">
<phing phingfile="build-propel.xml" target="graphviz"/>
</target>
</project>

View file

@ -0,0 +1,124 @@
<!--
Use this file to faciliate easy per-project building.
Simply create a build.properties file in this directory,
that contains any needed (i.e. to override) values for this project.
Call this build script and specify the name of the project and
(optionally) the name of the target you wish to execute (default is
'main' target) of build-propel.xml.
Normal use:
$> phing
Specific target:
$> phing -Dtarget=insert-sql
-->
<project name="propel-project-builder" default="main">
<!-- set to this dir -->
<property name="project.dir" value="."/>
<!-- set a default target if none provided -->
<property name="target" value="main"/>
<target name="buildpropescheck">
<available file="./build.properties" property="projBuildPopertiesExists"/>
</target>
<target name="init">
<echo msg="Loading project-specific props from ./build.properties"/>
<property file="./build.properties"/>
</target>
<target name="checkproject" unless="propel.project">
<fail msg="Build failed. Please make sure that propel.project is set to your project-name in local build.properties"/>
</target>
<target name="checkhome" unless="propel.home">
<fail msg="Build failed. Please make sure that propel.home is set to the propel-generator-dir in local build.properties"/>
</target>
<target name="checkschemadir" unless="propel.schema.dir">
<fail msg="Build failed. Please make sure that propel.schema.dir is set to '.' in local build.properties"/>
</target>
<target name="checkconfdir" unless="propel.conf.dir">
<fail msg="Build failed. Please make sure that propel.conf.dir is set to '.' in local build.properties"/>
</target>
<target name="checkoutputdir" unless="propel.output.dir">
<fail msg="Build failed. Please make sure that propel.output.dir is set to a directory of your choice (e.g. './build/') local build.properties"/>
</target>
<target name="configure" depends="init,checkproject,checkhome,checkschemadir,checkconfdir,checkoutputdir">
<property name="project" value="{$propel.project}"/>
</target>
<target name="main" depends="configure"
description="The main target. Includes project-specific build.properties and calls the build-propel.xml script">
<phing phingfile="${propel.home}/build-propel.xml" target="${target}"/>
</target>
<!--
Convenience mappings to build-propel.xml main targets
This makes it possible to use this buildfile w/o needing to specify
target as a property, e.g.:
$> phing -Dproject=bookstore insert-sql
The main reason for this is just consistency w/ old build-propel.xml file
(primarily for documentation & user confusion avoidance reasons). There are relatively
few & infrequently changing main targets of build-propel.xml, so it's a non-
issue as far as maintenance is concerned.
-->
<target name="convert-props" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="convert-props"/>
</target>
<target name="create-db" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="create-db"/>
</target>
<target name="creole" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="creole"/>
</target>
<target name="datadtd" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="datadtd"/>
</target>
<target name="datadump" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="datadump"/>
</target>
<target name="datasql" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="datasql"/>
</target>
<target name="insert-sql" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="insert-sql"/>
</target>
<target name="om" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="om"/>
</target>
<target name="new-om" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="new-om"/>
</target>
<target name="sql" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="sql"/>
</target>
<target name="old-sql" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="old-sql"/>
</target>
<target name="graphviz" depends="configure">
<phing phingfile="${propel.home}/build-propel.xml" target="graphviz"/>
</target>
</project>

View file

@ -0,0 +1,267 @@
# -------------------------------------------------------------------
#
# D E F A U L T P R O P E R T I E S
#
# -------------------------------------------------------------------
# This file sets default properties. You can override any of these
# by specifying your new value in the build.properties file for your
# project or a top-level build.properties file. Either way, you
# should not need to edit this file.
# -------------------------------------------------------------------
# -------------------------------------------------------------------
#
# B A S I C P R O P E R T I E S
#
# -------------------------------------------------------------------
propel.version = 1.5.2
propel.home = .
propel.project =
propel.database =
propel.targetPackage = ${propel.project}
propel.runOnlyOnSchemaChange = false
# Default behavior settings
#
propel.targetPlatform = php5
propel.packageObjectModel = false
propel.useDateTimeClass = true
propel.dateTimeClass = DateTime
propel.schema.validate = true
propel.schema.transform = false
# controls what type of joins will be used in the doSelectJoin*() peer methods,
# if set to true, LEFT JOINS will be used, INNER JOINS otherwise
# see ticket #491, #588
propel.useLeftJoinsInDoJoinMethods = true
# -------------------------------------------------------------------
#
# D A T A B A S E S E T T I N G S
#
# -------------------------------------------------------------------
propel.database.url =
propel.database.buildUrl = ${propel.database.url}
propel.database.createUrl = ${propel.database.buildUrl}
propel.database.driver =
propel.database.schema =
propel.database.encoding =
propel.database.manualCreation = false
# if these arent blank then when we try to connect with insert-sql to a database
# that doesnt require them and it isnt in the build.properties it sends
# the ${blah} for the username and password
propel.database.user =
propel.database.password =
# -------------------------------------------------------------------
#
# D A T A B A S E T O X M L S E T T I N G S
#
# -------------------------------------------------------------------
propel.samePhpName = false
propel.addVendorInfo = false
propel.addValidators = none
# -------------------------------------------------------------------
#
# T E M P L A T E V A R I A B L E S
#
# -------------------------------------------------------------------
propel.addGenericAccessors = true
propel.addGenericMutators = true
propel.addSaveMethod = true
propel.addTimeStamp = false
propel.addValidateMethod = true
propel.addIncludes = false
propel.addHooks = true
propel.basePrefix = Base
propel.saveException = PropelException
propel.emulateForeignKeyConstraints = false
# Identifier quoting is only implemented at the DDL layer at this point.
# Since this may result in undesired behavior (especially in Postgres),
# it can be disabled by setting this property to true in your build.properties file.
propel.disableIdentifierQuoting = false
# These are the default formats that will be used when fetching values
# from temporal columns in Propel. You can always specify these when
# calling the methods directly, but for methods like getByName()
# it is nice to change the defaults.
propel.defaultTimeStampFormat = Y-m-d H:i:s
propel.defaultTimeFormat = %X
propel.defaultDateFormat = %x
propel.namespace.om = om
propel.namespace.map = map
propel.namespace.autoPackage = false
propel.omtar.src.base = false
propel.omtar.src.extension = false
propel.omtar.bin.base = false
propel.omtar.bin.extension = false
propel.omtar.deleteFiles = false
# -------------------------------------------------------------------
#
# D I R E C T O R I E S
#
# -------------------------------------------------------------------
propel.project.dir = ${propel.home}/projects/${propel.project}
propel.output.dir = ${propel.project.dir}/build
propel.schema.dir = ${propel.project.dir}
propel.templatePath = ${propel.home}/templates
propel.conf.dir = ${propel.project.dir}
propel.doc.dir = ${propel.output.dir}/doc
propel.php.dir = ${propel.output.dir}/classes
propel.phpconf.dir = ${propel.output.dir}/conf
propel.phpdoc.dir = ${propel.output.dir}/phpdoc
propel.sql.dir = ${propel.output.dir}/sql
propel.graph.dir = ${propel.output.dir}/graph
propel.omtar.dir = ${propel.output.dir}
# -------------------------------------------------------------------
#
# D E F A U L T F I L E N A M ES
#
# -------------------------------------------------------------------
# propel.sqlfile
propel.runtime.conf.file = runtime-conf.xml
propel.runtime.phpconf.file = ${propel.project}-conf.php
propel.runtime.phpconf-classmap.file = ${propel.project}-classmap.php
propel.default.schema.basename = schema
# Can't use because of inconsistencies in where the files
# are named (some from build-propel.xml, but some from within templates)
# propel.default.data.basename = ${propel.project}-data
propel.schema.xsd.file = ${propel.home}/resources/xsd/database.xsd
propel.schema.xsl.file = ${propel.home}/resources/xsl/database.xsl
# -------------------------------------------------------------------
#
# I N C L U D E A N D E X C L U D E S E T T I N G S
#
# -------------------------------------------------------------------
propel.schema.sql.includes = *schema.xml
propel.schema.sql.excludes =
propel.schema.doc.includes = *schema.xml
propel.schema.doc.excludes =
propel.schema.create-db.includes = *schema.xml
propel.schema.create-db.excludes =
propel.schema.init-sql.includes = *schema.xml
propel.schema.init-sql.excludes = id-table-schema.xml
propel.schema.om.includes = *schema.xml
propel.schema.om.excludes = id-table-schema.xml
propel.schema.datadtd.includes = *schema.xml
propel.schema.datadtd.excludes = id-table-schema.xml
# -------------------------------------------------------------------
#
# M A P P E R S E T T I N G S
#
# -------------------------------------------------------------------
# (note: data xml files are selected based on datadbmap file)
propel.datasql.mapper.from = *.xml
propel.datasql.mapper.to = *.sql
propel.datadump.mapper.from = *schema.xml
propel.datadump.mapper.to = *data.xml
propel.datadtd.mapper.from = *.xml
propel.datadtd.mapper.to = *.dtd
propel.sql.mapper.from = *.xml
propel.sql.mapper.to = *.sql
# -------------------------------------------------------------------
#
# B U I L D E R S E T T I N G S
#
# -------------------------------------------------------------------
# Object Model builders
propel.builder.peer.class = builder.om.PHP5PeerBuilder
propel.builder.object.class = builder.om.PHP5ObjectBuilder
propel.builder.objectstub.class = builder.om.PHP5ExtensionObjectBuilder
propel.builder.peerstub.class = builder.om.PHP5ExtensionPeerBuilder
propel.builder.objectmultiextend.class = builder.om.PHP5MultiExtendObjectBuilder
propel.builder.tablemap.class = builder.om.PHP5TableMapBuilder
propel.builder.query.class = builder.om.QueryBuilder
propel.builder.querystub.class = builder.om.ExtensionQueryBuilder
propel.builder.queryinheritance.class = builder.om.QueryInheritanceBuilder
propel.builder.queryinheritancestub.class = builder.om.ExtensionQueryInheritanceBuilder
propel.builder.interface.class = builder.om.PHP5InterfaceBuilder
propel.builder.node.class = builder.om.PHP5NodeBuilder
propel.builder.nodepeer.class = builder.om.PHP5NodePeerBuilder
propel.builder.nodestub.class = builder.om.PHP5ExtensionNodeBuilder
propel.builder.nodepeerstub.class = builder.om.PHP5ExtensionNodePeerBuilder
propel.builder.nestedset.class = builder.om.PHP5NestedSetBuilder
propel.builder.nestedsetpeer.class = builder.om.PHP5NestedSetPeerBuilder
propel.builder.pluralizer.class = builder.util.DefaultEnglishPluralizer
# SQL builders
propel.builder.ddl.class = builder.sql.${propel.database}.${propel.database}DDLBuilder
propel.builder.datasql.class = builder.sql.${propel.database}.${propel.database}DataSQLBuilder
# Platform classes
propel.platform.class = platform.${propel.database}Platform
# Schema Parser (reverse-engineering) classes
propel.reverse.parser.class = reverse.${propel.database}.${propel.database}SchemaParser
# -------------------------------------------------------------------
#
# M Y S Q L S P E C I F I C S E T T I N G S
#
# -------------------------------------------------------------------
# Default table type
propel.mysqlTableType = MyISAM
# Keyword used to specify table type. MYSQL < 5 should use TYPE instead
propel.mysqlTableEngineKeyword = ENGINE
# -------------------------------------------------------------------
#
# B E H A V I O R S E T T I N G S
#
# -------------------------------------------------------------------
propel.behavior.timestampable.class = behavior.TimestampableBehavior
propel.behavior.alternative_coding_standards.class = behavior.AlternativeCodingStandardsBehavior
propel.behavior.soft_delete.class = behavior.SoftDeleteBehavior
propel.behavior.auto_add_pk.class = behavior.AutoAddPkBehavior
propel.behavior.nested_set.class = behavior.nestedset.NestedSetBehavior
propel.behavior.sortable.class = behavior.sortable.SortableBehavior
propel.behavior.sluggable.class = behavior.sluggable.SluggableBehavior
propel.behavior.concrete_inheritance.class = behavior.concrete_inheritance.ConcreteInheritanceBehavior
propel.behavior.query_cache.class = behavior.query_cache.QueryCacheBehavior
propel.behavior.aggregate_column.class = behavior.aggregate_column.AggregateColumnBehavior

View file

@ -0,0 +1,133 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Changes the coding standard of Propel generated Model classes
* - Opening brackets always use newline, e.g.
* if ($foo) {
* ...
* } else {
* ...
* }
* Becomes:
* if ($foo)
* {
* ...
* }
* else
* {
* ...
* }
* - closing comments are removed, e.g.
* } // save()
* Becomes:
* }
* - tabs are replaced by 2 whitespaces
* - comments are stripped (optional)
*
* @author François Zaninotto
* @version $Revision: 1612 $
* @package propel.generator.behavior
*/
class AlternativeCodingStandardsBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'brackets_newline' => 'true',
'remove_closing_comments' => 'true',
'use_whitespace' => 'true',
'tab_size' => 2,
'strip_comments' => 'false'
);
public function objectFilter(&$script)
{
return $this->filter($script);
}
public function extensionObjectFilter(&$script)
{
return $this->filter($script);
}
public function queryFilter(&$script)
{
return $this->filter($script);
}
public function extensionQueryFilter(&$script)
{
return $this->filter($script);
}
public function peerFilter(&$script)
{
return $this->filter($script);
}
public function extensionPeerFilter(&$script)
{
return $this->filter($script);
}
public function tableMapFilter(&$script)
{
return $this->filter($script);
}
/**
* Transform the coding standards of a PHP sourcecode string
*
* @param string $script A script string to be filtered, passed as reference
*/
protected function filter(&$script)
{
$filter = array();
if($this->getParameter('brackets_newline') == 'true') {
$filter['#^(\t*)\}\h(else|elseif|catch)(.*)\h\{$#m'] = "$1}
$1$2$3
$1{";
$filter['#^(\t*)(\w.*)\h\{$#m'] = "$1$2
$1{";
}
if ($this->getParameter('remove_closing_comments') == 'true') {
$filter['#^(\t*)} //.*$#m'] = "$1}";
}
if ($this->getParameter('use_whitespace') == 'true') {
$filter['#\t#'] = str_repeat(' ', $this->getParameter('tab_size'));
}
$script = preg_replace(array_keys($filter), array_values($filter), $script);
if ($this->getParameter('strip_comments') == 'true') {
$script = self::stripComments($script);
}
}
/**
* Remove inline and codeblock comments from a PHP code string
* @param string $code The input code
* @return string The input code, without comments
*/
public static function stripComments($code)
{
$output = '';
$commentTokens = array(T_COMMENT, T_DOC_COMMENT);
foreach (token_get_all($code) as $token) {
if (is_array($token)) {
if (in_array($token[0], $commentTokens)) continue;
$token = $token[1];
}
$output .= $token;
}
return $output;
}
}

View file

@ -0,0 +1,54 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Adds a primary key to models defined without one
*
* @author François Zaninotto
* @version $Revision: 1745 $
* @package propel.generator.behavior
*/
class AutoAddPkBehavior extends Behavior
{
protected $isEarly = true;
// default parameters value
protected $parameters = array(
'name' => 'id',
'autoIncrement' => 'true',
'type' => 'INTEGER'
);
/**
* Copy the behavior to the database tables
* Only for tables that have no Pk
*/
public function modifyDatabase()
{
foreach ($this->getDatabase()->getTables() as $table) {
if(!$table->hasPrimaryKey()) {
$b = clone $this;
$table->addBehavior($b);
}
}
}
/**
* Add the primary key to the current table
*/
public function modifyTable()
{
$table = $this->getTable();
if (!$table->hasPrimaryKey() && !$table->hasBehavior('concrete_inheritance')) {
$columnAttributes = array_merge(array('primaryKey' => 'true'), $this->getParameters());
$this->getTable()->addColumn($columnAttributes);
}
}
}

View file

@ -0,0 +1,467 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Gives a model class the ability to remain in database even when the user deletes object
* Uses an additional column storing the deletion date
* And an additional condition for every read query to only consider rows with no deletion date
*
* @author François Zaninotto
* @version $Revision: 1807 $
* @package propel.generator.behavior
*/
class SoftDeleteBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'deleted_column' => 'deleted_at',
);
/**
* Add the deleted_column to the current table
*/
public function modifyTable()
{
if(!$this->getTable()->containsColumn($this->getParameter('deleted_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('deleted_column'),
'type' => 'TIMESTAMP'
));
}
}
protected function getColumnSetter()
{
return 'set' . $this->getColumnForParameter('deleted_column')->getPhpName();
}
public function objectMethods($builder)
{
$script = '';
$this->addObjectForceDelete($script);
$this->addObjectUndelete($script);
return $script;
}
public function addObjectForceDelete(&$script)
{
$script .= "
/**
* Bypass the soft_delete behavior and force a hard delete of the current object
*/
public function forceDelete(PropelPDO \$con = null)
{
{$this->getTable()->getPhpName()}Peer::disableSoftDelete();
\$this->delete(\$con);
}
";
}
public function addObjectUndelete(&$script)
{
$script .= "
/**
* Undelete a row that was soft_deleted
*
* @return int The number of rows affected by this update and any referring fk objects' save() operations.
*/
public function unDelete(PropelPDO \$con = null)
{
\$this->{$this->getColumnSetter()}(null);
return \$this->save(\$con);
}
";
}
public function preDelete($builder)
{
return <<<EOT
if (!empty(\$ret) && {$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled()) {
\$this->{$this->getColumnSetter()}(time());
\$this->save(\$con);
\$con->commit();
{$builder->getStubPeerBuilder()->getClassname()}::removeInstanceFromPool(\$this);
return;
}
EOT;
}
public function queryAttributes()
{
return "protected static \$softDelete = true;
protected \$localSoftDelete = true;
";
}
public function queryMethods($builder)
{
$this->builder = $builder;
$script = '';
$this->addQueryIncludeDeleted($script);
$this->addQuerySoftDelete($script);
$this->addQueryForceDelete($script);
$this->addQueryForceDeleteAll($script);
$this->addQueryUnDelete($script);
$this->addQueryEnableSoftDelete($script);
$this->addQueryDisableSoftDelete($script);
$this->addQueryIsSoftDeleteEnabled($script);
return $script;
}
public function addQueryIncludeDeleted(&$script)
{
$script .= "
/**
* Temporarily disable the filter on deleted rows
* Valid only for the current query
*
* @see {$this->builder->getStubQueryBuilder()->getClassname()}::disableSoftDelete() to disable the filter for more than one query
*
* @return {$this->builder->getStubQueryBuilder()->getClassname()} The current query, for fuid interface
*/
public function includeDeleted()
{
\$this->localSoftDelete = false;
return \$this;
}
";
}
public function addQuerySoftDelete(&$script)
{
$script .= "
/**
* Soft delete the selected rows
*
* @param PropelPDO \$con an optional connection object
*
* @return int Number of updated rows
*/
public function softDelete(PropelPDO \$con = null)
{
return \$this->update(array('{$this->getColumnForParameter('deleted_column')->getPhpName()}' => time()), \$con);
}
";
}
public function addQueryForceDelete(&$script)
{
$script .= "
/**
* Bypass the soft_delete behavior and force a hard delete of the selected rows
*
* @param PropelPDO \$con an optional connection object
*
* @return int Number of deleted rows
*/
public function forceDelete(PropelPDO \$con = null)
{
return {$this->builder->getPeerClassname()}::doForceDelete(\$this, \$con);
}
";
}
public function addQueryForceDeleteAll(&$script)
{
$script .= "
/**
* Bypass the soft_delete behavior and force a hard delete of all the rows
*
* @param PropelPDO \$con an optional connection object
*
* @return int Number of deleted rows
*/
public function forceDeleteAll(PropelPDO \$con = null)
{
return {$this->builder->getPeerClassname()}::doForceDeleteAll(\$con);}
";
}
public function addQueryUnDelete(&$script)
{
$script .= "
/**
* Undelete selected rows
*
* @param PropelPDO \$con an optional connection object
*
* @return int The number of rows affected by this update and any referring fk objects' save() operations.
*/
public function unDelete(PropelPDO \$con = null)
{
return \$this->update(array('{$this->getColumnForParameter('deleted_column')->getPhpName()}' => null), \$con);
}
";
}
public function addQueryEnableSoftDelete(&$script)
{
$script .= "
/**
* Enable the soft_delete behavior for this model
*/
public static function enableSoftDelete()
{
self::\$softDelete = true;
}
";
}
public function addQueryDisableSoftDelete(&$script)
{
$script .= "
/**
* Disable the soft_delete behavior for this model
*/
public static function disableSoftDelete()
{
self::\$softDelete = false;
}
";
}
public function addQueryIsSoftDeleteEnabled(&$script)
{
$script .= "
/**
* Check the soft_delete behavior for this model
*
* @return boolean true if the soft_delete behavior is enabled
*/
public static function isSoftDeleteEnabled()
{
return self::\$softDelete;
}
";
}
public function preSelectQuery($builder)
{
return <<<EOT
if ({$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled() && \$this->localSoftDelete) {
\$this->addUsingAlias({$this->getColumnForParameter('deleted_column')->getConstantName()}, null, Criteria::ISNULL);
} else {
{$this->getTable()->getPhpName()}Peer::enableSoftDelete();
}
EOT;
}
public function preDeleteQuery($builder)
{
return <<<EOT
if ({$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled() && \$this->localSoftDelete) {
return \$this->softDelete(\$con);
} else {
return \$this->hasWhereClause() ? \$this->forceDelete(\$con) : \$this->forceDeleteAll(\$con);
}
EOT;
}
public function staticMethods($builder)
{
$builder->declareClassFromBuilder($builder->getStubQueryBuilder());
$this->builder = $builder;
$script = '';
$this->addPeerEnableSoftDelete($script);
$this->addPeerDisableSoftDelete($script);
$this->addPeerIsSoftDeleteEnabled($script);
$this->addPeerDoSoftDelete($script);
$this->addPeerDoDelete2($script);
$this->addPeerDoSoftDeleteAll($script);
$this->addPeerDoDeleteAll2($script);
return $script;
}
public function addPeerEnableSoftDelete(&$script)
{
$script .= "
/**
* Enable the soft_delete behavior for this model
*/
public static function enableSoftDelete()
{
{$this->builder->getStubQueryBuilder()->getClassname()}::enableSoftDelete();
// some soft_deleted objects may be in the instance pool
{$this->builder->getStubPeerBuilder()->getClassname()}::clearInstancePool();
}
";
}
public function addPeerDisableSoftDelete(&$script)
{
$script .= "
/**
* Disable the soft_delete behavior for this model
*/
public static function disableSoftDelete()
{
{$this->builder->getStubQueryBuilder()->getClassname()}::disableSoftDelete();
}
";
}
public function addPeerIsSoftDeleteEnabled(&$script)
{
$script .= "
/**
* Check the soft_delete behavior for this model
* @return boolean true if the soft_delete behavior is enabled
*/
public static function isSoftDeleteEnabled()
{
return {$this->builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled();
}
";
}
public function addPeerDoSoftDelete(&$script)
{
$script .= "
/**
* Soft delete records, given a {$this->getTable()->getPhpName()} or Criteria object OR a primary key value.
*
* @param mixed \$values Criteria or {$this->getTable()->getPhpName()} object or primary key or array of primary keys
* which is used to create the DELETE statement
* @param PropelPDO \$con the connection to use
* @return int The number of affected rows (if supported by underlying database driver).
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function doSoftDelete(\$values, PropelPDO \$con = null)
{
if (\$values instanceof Criteria) {
// rename for clarity
\$criteria = clone \$values;
} elseif (\$values instanceof {$this->getTable()->getPhpName()}) {
// create criteria based on pk values
\$criteria = \$values->buildPkeyCriteria();
} else {
// it must be the primary key
\$criteria = new Criteria(self::DATABASE_NAME);";
$pks = $this->getTable()->getPrimaryKey();
if (count($pks)>1) {
$i = 0;
foreach ($pks as $col) {
$script .= "
\$criteria->add({$col->getConstantName()}, \$values[$i], Criteria::EQUAL);";
$i++;
}
} else {
$col = $pks[0];
$script .= "
\$criteria->add({$col->getConstantName()}, (array) \$values, Criteria::IN);";
}
$script .= "
}
\$criteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, time());
return {$this->getTable()->getPhpName()}Peer::doUpdate(\$criteria, \$con);
}
";
}
public function addPeerDoDelete2(&$script)
{
$script .= "
/**
* Delete or soft delete records, depending on {$this->getTable()->getPhpName()}Peer::\$softDelete
*
* @param mixed \$values Criteria or {$this->getTable()->getPhpName()} object or primary key or array of primary keys
* which is used to create the DELETE statement
* @param PropelPDO \$con the connection to use
* @return int The number of affected rows (if supported by underlying database driver).
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function doDelete2(\$values, PropelPDO \$con = null)
{
if ({$this->getTable()->getPhpName()}Peer::isSoftDeleteEnabled()) {
return {$this->getTable()->getPhpName()}Peer::doSoftDelete(\$values, \$con);
} else {
return {$this->getTable()->getPhpName()}Peer::doForceDelete(\$values, \$con);
}
}";
}
public function addPeerDoSoftDeleteAll(&$script)
{
$script .= "
/**
* Method to soft delete all rows from the {$this->getTable()->getName()} table.
*
* @param PropelPDO \$con the connection to use
* @return int The number of affected rows (if supported by underlying database driver).
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function doSoftDeleteAll(PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection({$this->getTable()->getPhpName()}Peer::DATABASE_NAME, Propel::CONNECTION_WRITE);
}
\$selectCriteria = new Criteria();
\$selectCriteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, null, Criteria::ISNULL);
\$selectCriteria->setDbName({$this->getTable()->getPhpName()}Peer::DATABASE_NAME);
\$modifyCriteria = new Criteria();
\$modifyCriteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, time());
return BasePeer::doUpdate(\$selectCriteria, \$modifyCriteria, \$con);
}
";
}
public function addPeerDoDeleteAll2(&$script)
{
$script .= "
/**
* Delete or soft delete all records, depending on {$this->getTable()->getPhpName()}Peer::\$softDelete
*
* @param PropelPDO \$con the connection to use
* @return int The number of affected rows (if supported by underlying database driver).
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function doDeleteAll2(PropelPDO \$con = null)
{
if ({$this->getTable()->getPhpName()}Peer::isSoftDeleteEnabled()) {
return {$this->getTable()->getPhpName()}Peer::doSoftDeleteAll(\$con);
} else {
return {$this->getTable()->getPhpName()}Peer::doForceDeleteAll(\$con);
}
}
";
}
public function preSelect($builder)
{
return <<<EOT
if ({$builder->getStubQueryBuilder()->getClassname()}::isSoftDeleteEnabled()) {
\$criteria->add({$this->getColumnForParameter('deleted_column')->getConstantName()}, null, Criteria::ISNULL);
} else {
{$this->getTable()->getPhpName()}Peer::enableSoftDelete();
}
EOT;
}
public function peerFilter(&$script)
{
$script = str_replace(array(
'public static function doDelete(',
'public static function doDelete2(',
'public static function doDeleteAll(',
'public static function doDeleteAll2('
), array(
'public static function doForceDelete(',
'public static function doDelete(',
'public static function doForceDeleteAll(',
'public static function doDeleteAll('
), $script);
}
}

View file

@ -0,0 +1,171 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Gives a model class the ability to track creation and last modification dates
* Uses two additional columns storing the creation and update date
*
* @author François Zaninotto
* @version $Revision: 1683 $
* @package propel.generator.behavior
*/
class TimestampableBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'create_column' => 'created_at',
'update_column' => 'updated_at'
);
/**
* Add the create_column and update_columns to the current table
*/
public function modifyTable()
{
if(!$this->getTable()->containsColumn($this->getParameter('create_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('create_column'),
'type' => 'TIMESTAMP'
));
}
if(!$this->getTable()->containsColumn($this->getParameter('update_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('update_column'),
'type' => 'TIMESTAMP'
));
}
}
/**
* Get the setter of one of the columns of the behavior
*
* @param string $column One of the behavior colums, 'create_column' or 'update_column'
* @return string The related setter, 'setCreatedOn' or 'setUpdatedOn'
*/
protected function getColumnSetter($column)
{
return 'set' . $this->getColumnForParameter($column)->getPhpName();
}
/**
* Add code in ObjectBuilder::preUpdate
*
* @return string The code to put at the hook
*/
public function preUpdate()
{
return "if (\$this->isModified() && !\$this->isColumnModified(" . $this->getColumnForParameter('update_column')->getConstantName() . ")) {
\$this->" . $this->getColumnSetter('update_column') . "(time());
}";
}
/**
* Add code in ObjectBuilder::preInsert
*
* @return string The code to put at the hook
*/
public function preInsert()
{
return "if (!\$this->isColumnModified(" . $this->getColumnForParameter('create_column')->getConstantName() . ")) {
\$this->" . $this->getColumnSetter('create_column') . "(time());
}
if (!\$this->isColumnModified(" . $this->getColumnForParameter('update_column')->getConstantName() . ")) {
\$this->" . $this->getColumnSetter('update_column') . "(time());
}";
}
public function objectMethods($builder)
{
return "
/**
* Mark the current object so that the update date doesn't get updated during next save
*
* @return " . $builder->getStubObjectBuilder()->getClassname() . " The current object (for fluent API support)
*/
public function keepUpdateDateUnchanged()
{
\$this->modifiedColumns[] = " . $this->getColumnForParameter('update_column')->getConstantName() . ";
return \$this;
}
";
}
public function queryMethods($builder)
{
$queryClassName = $builder->getStubQueryBuilder()->getClassname();
$updateColumnConstant = $this->getColumnForParameter('update_column')->getConstantName();
$createColumnConstant = $this->getColumnForParameter('create_column')->getConstantName();
return "
/**
* Filter by the latest updated
*
* @param int \$nbDays Maximum age of the latest update in days
*
* @return $queryClassName The current query, for fuid interface
*/
public function recentlyUpdated(\$nbDays = 7)
{
return \$this->addUsingAlias($updateColumnConstant, time() - \$nbDays * 24 * 60 * 60, Criteria::GREATER_EQUAL);
}
/**
* Filter by the latest created
*
* @param int \$nbDays Maximum age of in days
*
* @return $queryClassName The current query, for fuid interface
*/
public function recentlyCreated(\$nbDays = 7)
{
return \$this->addUsingAlias($createColumnConstant, time() - \$nbDays * 24 * 60 * 60, Criteria::GREATER_EQUAL);
}
/**
* Order by update date desc
*
* @return $queryClassName The current query, for fuid interface
*/
public function lastUpdatedFirst()
{
return \$this->addDescendingOrderByColumn($updateColumnConstant);
}
/**
* Order by update date asc
*
* @return $queryClassName The current query, for fuid interface
*/
public function firstUpdatedFirst()
{
return \$this->addAscendingOrderByColumn($updateColumnConstant);
}
/**
* Order by create date desc
*
* @return $queryClassName The current query, for fuid interface
*/
public function lastCreatedFirst()
{
return \$this->addDescendingOrderByColumn($createColumnConstant);
}
/**
* Order by create date asc
*
* @return $queryClassName The current query, for fuid interface
*/
public function firstCreatedFirst()
{
return \$this->addAscendingOrderByColumn($createColumnConstant);
}
";
}
}

View file

@ -0,0 +1,122 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'AggregateColumnRelationBehavior.php';
/**
* Keeps an aggregate column updated with related table
*
* @author François Zaninotto
* @version $Revision: 1785 $
* @package propel.generator.behavior.aggregate_column
*/
class AggregateColumnBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'name' => null,
'expression' => null,
'foreign_table' => null,
);
/**
* Add the aggregate key to the current table
*/
public function modifyTable()
{
$table = $this->getTable();
if (!$columnName = $this->getParameter('name')) {
throw new InvalidArgumentException(sprintf('You must define a \'name\' parameter for the \'aggregate_column\' behavior in the \'%s\' table', $table->getName()));
}
// add the aggregate column if not present
if(!$this->getTable()->containsColumn($columnName)) {
$column = $this->getTable()->addColumn(array(
'name' => $columnName,
'type' => 'INTEGER',
));
}
// add a behavior in the foreign table to autoupdate the aggregate column
$foreignTable = $this->getForeignTable();
if (!$foreignTable->hasBehavior('concrete_inheritance_parent')) {
$relationBehavior = new AggregateColumnRelationBehavior();
$relationBehavior->setName('aggregate_column_relation');
$foreignKey = $this->getForeignKey();
$relationBehavior->addParameter(array('name' => 'foreign_table', 'value' => $table->getName()));
$relationBehavior->addParameter(array('name' => 'update_method', 'value' => 'update' . $this->getColumn()->getPhpName()));
$foreignTable->addBehavior($relationBehavior);
}
}
public function objectMethods($builder)
{
if (!$foreignTableName = $this->getParameter('foreign_table')) {
throw new InvalidArgumentException(sprintf('You must define a \'foreign_table\' parameter for the \'aggregate_column\' behavior in the \'%s\' table', $this->getTable()->getName()));
}
$script = '';
$script .= $this->addObjectCompute();
$script .= $this->addObjectUpdate();
return $script;
}
protected function addObjectCompute()
{
$conditions = array();
$bindings = array();
foreach ($this->getForeignKey()->getColumnObjectsMapping() as $index => $columnReference) {
$conditions[] = $columnReference['local']->getFullyQualifiedName() . ' = :p' . ($index + 1);
$bindings[$index + 1] = $columnReference['foreign']->getPhpName();
}
$sql = sprintf('SELECT %s FROM %s WHERE %s',
$this->getParameter('expression'),
$this->getTable()->getDatabase()->getPlatform()->quoteIdentifier($this->getParameter('foreign_table')),
implode(' AND ', $conditions)
);
return $this->renderTemplate('objectCompute', array(
'column' => $this->getColumn(),
'sql' => $sql,
'bindings' => $bindings,
));
}
protected function addObjectUpdate()
{
return $this->renderTemplate('objectUpdate', array(
'column' => $this->getColumn(),
));
}
protected function getForeignTable()
{
return $this->getTable()->getDatabase()->getTable($this->getParameter('foreign_table'));
}
protected function getForeignKey()
{
$foreignTable = $this->getForeignTable();
// let's infer the relation from the foreign table
$fks = $foreignTable->getForeignKeysReferencingTable($this->getTable()->getName());
if (!$fks) {
throw new InvalidArgumentException(sprintf('You must define a foreign key to the \'%s\' table in the \'%s\' table to enable the \'aggregate_column\' behavior', $this->getTable()->getName(), $foreignTable->getName()));
}
// FIXME doesn't work when more than one fk to the same table
return array_shift($fks);
}
protected function getColumn()
{
return $this->getTable()->getColumn($this->getParameter('name'));
}
}

View file

@ -0,0 +1,164 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'AggregateColumnRelationBehavior.php';
/**
* Keeps an aggregate column updated with related table
*
* @author François Zaninotto
* @version $Revision: 1785 $
* @package propel.generator.behavior.aggregate_column
*/
class AggregateColumnRelationBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'foreign_table' => '',
'update_method' => '',
);
public function postSave($builder)
{
$relationName = $this->getRelationName($builder);
return "\$this->updateRelated{$relationName}(\$con);";
}
// no need for a postDelete() hook, since delete() uses Query::delete(),
// which already has a hook
public function objectAttributes($builder)
{
$relationName = $this->getRelationName($builder);
return "protected \$old{$relationName};
";
}
public function objectMethods($builder)
{
return $this->addObjectUpdateRelated($builder);
}
protected function addObjectUpdateRelated($builder)
{
$relationName = $this->getRelationName($builder);
$updateMethodName = $this->getParameter('update_method');
return $this->renderTemplate('objectUpdateRelated', array(
'relationName' => $relationName,
'variableName' => self::lcfirst($relationName),
'updateMethodName' => $this->getParameter('update_method'),
));
}
public function objectFilter(&$script, $builder)
{
$relationName = $this->getRelationName($builder);
$relatedClass = $this->getForeignTable()->getPhpName();
$search = " public function set{$relationName}({$relatedClass} \$v = null)
{";
$replace = $search . "
// aggregate_column_relation behavior
if (null !== \$this->a{$relationName} && \$v !== \$this->a{$relationName}) {
\$this->old{$relationName} = \$this->a{$relationName};
}";
$script = str_replace($search, $replace, $script);
}
public function preUpdateQuery($builder)
{
return $this->getFindRelated($builder);
}
public function preDeleteQuery($builder)
{
return $this->getFindRelated($builder);
}
protected function getFindRelated($builder)
{
$relationName = $this->getRelationName($builder);
return "\$this->findRelated{$relationName}s(\$con);";
}
public function postUpdateQuery($builder)
{
return $this->getUpdateRelated($builder);
}
public function postDeleteQuery($builder)
{
return $this->getUpdateRelated($builder);
}
protected function getUpdateRelated($builder)
{
$relationName = $this->getRelationName($builder);
return "\$this->updateRelated{$relationName}s(\$con);";
}
public function queryMethods($builder)
{
$script = '';
$script .= $this->addQueryFindRelated($builder);
$script .= $this->addQueryUpdateRelated($builder);
return $script;
}
protected function addQueryFindRelated($builder)
{
$foreignKey = $this->getForeignKey();
$relationName = $this->getRelationName($builder);
return $this->renderTemplate('queryFindRelated', array(
'foreignTable' => $this->getForeignTable(),
'relationName' => $relationName,
'variableName' => self::lcfirst($relationName),
'foreignQueryName' => $foreignKey->getForeignTable()->getPhpName() . 'Query',
'refRelationName' => $builder->getRefFKPhpNameAffix($foreignKey),
));
}
protected function addQueryUpdateRelated($builder)
{
$relationName = $this->getRelationName($builder);
return $this->renderTemplate('queryUpdateRelated', array(
'relationName' => $relationName,
'variableName' => self::lcfirst($relationName),
'updateMethodName' => $this->getParameter('update_method'),
));
}
protected function getForeignTable()
{
return $this->getTable()->getDatabase()->getTable($this->getParameter('foreign_table'));
}
protected function getForeignKey()
{
$foreignTable = $this->getForeignTable();
// let's infer the relation from the foreign table
$fks = $this->getTable()->getForeignKeysReferencingTable($foreignTable->getName());
// FIXME doesn't work when more than one fk to the same table
return array_shift($fks);
}
protected function getRelationName($builder)
{
return $builder->getFKPhpNameAffix($this->getForeignKey());
}
protected static function lcfirst($input)
{
// no lcfirst in php<5.3...
$input[0] = strtolower($input[0]);
return $input;
}
}

View file

@ -0,0 +1,17 @@
/**
* Computes the value of the aggregate column <?php echo $column->getName() ?>
*
* @param PropelPDO $con A connection object
*
* @return mixed The scalar result from the aggregate query
*/
public function compute<?php echo $column->getPhpName() ?>(PropelPDO $con)
{
$stmt = $con->prepare('<?php echo $sql ?>');
<?php foreach ($bindings as $key => $binding): ?>
$stmt->bindValue(':p<?php echo $key ?>', $this->get<?php echo $binding ?>());
<?php endforeach; ?>
$stmt->execute();
return $stmt->fetchColumn();
}

View file

@ -0,0 +1,11 @@
/**
* Updates the aggregate column <?php echo $column->getName() ?>
*
* @param PropelPDO $con A connection object
*/
public function update<?php echo $column->getPhpName() ?>(PropelPDO $con)
{
$this->set<?php echo $column->getPhpName() ?>($this->compute<?php echo $column->getPhpName() ?>($con));
$this->save($con);
}

View file

@ -0,0 +1,16 @@
/**
* Update the aggregate column in the related <?php echo $relationName ?> object
*
* @param PropelPDO $con A connection object
*/
protected function updateRelated<?php echo $relationName ?>(PropelPDO $con)
{
if ($<?php echo $variableName ?> = $this->get<?php echo $relationName ?>()) {
$<?php echo $variableName ?>-><?php echo $updateMethodName ?>($con);
}
if ($this->old<?php echo $relationName ?>) {
$this->old<?php echo $relationName ?>-><?php echo $updateMethodName ?>($con);
$this->old<?php echo $relationName ?> = null;
}
}

View file

@ -0,0 +1,20 @@
/**
* Finds the related <?php echo $foreignTable->getPhpName() ?> objects and keep them for later
*
* @param PropelPDO $con A connection object
*/
protected function findRelated<?php echo $relationName ?>s($con)
{
$criteria = clone $this;
if ($this->useAliasInSQL) {
$alias = $this->getModelAlias();
$criteria->removeAlias($alias);
} else {
$alias = '';
}
$this-><?php echo $variableName ?>s = <?php echo $foreignQueryName ?>::create()
->join<?php echo $refRelationName ?>($alias)
->mergeWith($criteria)
->find($con);
}

View file

@ -0,0 +1,8 @@
protected function updateRelated<?php echo $relationName ?>s($con)
{
foreach ($this-><?php echo $variableName ?>s as $<?php echo $variableName ?>) {
$<?php echo $variableName ?>-><?php echo $updateMethodName ?>($con);
}
$this-><?php echo $variableName ?>s = array();
}

View file

@ -0,0 +1,235 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'ConcreteInheritanceParentBehavior.php';
/**
* Gives a model class the ability to remain in database even when the user deletes object
* Uses an additional column storing the deletion date
* And an additional condition for every read query to only consider rows with no deletion date
*
* @author François Zaninotto
* @version $Revision: 1774 $
* @package propel.generator.behavior.concrete_inheritance
*/
class ConcreteInheritanceBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'extends' => '',
'descendant_column' => 'descendant_class',
'copy_data_to_parent' => 'true'
);
public function modifyTable()
{
$table = $this->getTable();
$parentTable = $this->getParentTable();
if ($this->isCopyData()) {
// tell the parent table that it has a descendant
if (!$parentTable->hasBehavior('concrete_inheritance_parent')) {
$parentBehavior = new ConcreteInheritanceParentBehavior();
$parentBehavior->setName('concrete_inheritance_parent');
$parentBehavior->addParameter(array('name' => 'descendant_column', 'value' => $this->getParameter('descendant_column')));
$parentTable->addBehavior($parentBehavior);
// The parent table's behavior modifyTable() must be executed before this one
$parentBehavior->getTableModifier()->modifyTable();
$parentBehavior->setTableModified(true);
}
}
// Add the columns of the parent table
foreach ($parentTable->getColumns() as $column) {
if ($column->getName() == $this->getParameter('descendant_column')) {
continue;
}
if ($table->containsColumn($column->getName())) {
continue;
}
$copiedColumn = clone $column;
if ($column->isAutoIncrement() && $this->isCopyData()) {
$copiedColumn->setAutoIncrement(false);
}
$table->addColumn($copiedColumn);
if ($column->isPrimaryKey() && $this->isCopyData()) {
$fk = new ForeignKey();
$fk->setForeignTableName($column->getTable()->getName());
$fk->setOnDelete('CASCADE');
$fk->setOnUpdate(null);
$fk->addReference($copiedColumn, $column);
$fk->isParentChild = true;
$table->addForeignKey($fk);
}
}
// add the foreign keys of the parent table
foreach ($parentTable->getForeignKeys() as $fk) {
$copiedFk = clone $fk;
$copiedFk->setName('');
$copiedFk->setRefPhpName('');
$this->getTable()->addForeignKey($copiedFk);
}
// add the validators of the parent table
foreach ($parentTable->getValidators() as $validator) {
$copiedValidator = clone $validator;
$this->getTable()->addValidator($copiedValidator);
}
// add the indices of the parent table
foreach ($parentTable->getIndices() as $index) {
$copiedIndex = clone $index;
$copiedIndex->setName('');
$this->getTable()->addIndex($copiedIndex);
}
// add the unique indices of the parent table
foreach ($parentTable->getUnices() as $unique) {
$copiedUnique = clone $unique;
$copiedUnique->setName('');
$this->getTable()->addUnique($copiedUnique);
}
// give name to newly added foreign keys and indices
// (this is already done for other elements of the current table)
$table->doNaming();
// add the Behaviors of the parent table
foreach ($parentTable->getBehaviors() as $behavior) {
if ($behavior->getName() == 'concrete_inheritance_parent' || $behavior->getName() == 'concrete_inheritance') {
continue;
}
$copiedBehavior = clone $behavior;
$this->getTable()->addBehavior($copiedBehavior);
}
}
protected function getParentTable()
{
return $this->getTable()->getDatabase()->getTable($this->getParameter('extends'));
}
protected function isCopyData()
{
return $this->getParameter('copy_data_to_parent') == 'true';
}
public function parentClass($builder)
{
switch (get_class($builder)) {
case 'PHP5ObjectBuilder':
return $builder->getNewStubObjectBuilder($this->getParentTable())->getClassname();
break;
case 'QueryBuilder':
return $builder->getNewStubQueryBuilder($this->getParentTable())->getClassname();
break;
default:
return null;
break;
}
}
public function preSave($script)
{
if ($this->isCopyData()) {
return "\$parent = \$this->getSyncParent(\$con);
\$parent->save(\$con);
\$this->setPrimaryKey(\$parent->getPrimaryKey());
";
}
}
public function postDelete($script)
{
if ($this->isCopyData()) {
return "\$this->getParentOrCreate(\$con)->delete(\$con);
";
}
}
public function objectMethods($builder)
{
if (!$this->isCopyData()) {
return;
}
$this->builder = $builder;
$script .= '';
$this->addObjectGetParentOrCreate($script);
$this->addObjectGetSyncParent($script);
return $script;
}
protected function addObjectGetParentOrCreate(&$script)
{
$parentTable = $this->getParentTable();
$parentClass = $this->builder->getNewStubObjectBuilder($parentTable)->getClassname();
$script .= "
/**
* Get or Create the parent " . $parentClass . " object of the current object
*
* @return " . $parentClass . " The parent object
*/
public function getParentOrCreate(\$con = null)
{
if (\$this->isNew()) {
\$parent = new " . $parentClass . "();
\$parent->set" . $this->getParentTable()->getColumn($this->getParameter('descendant_column'))->getPhpName() . "('" . $this->builder->getStubObjectBuilder()->getClassname() . "');
return \$parent;
} else {
return " . $this->builder->getNewStubQueryBuilder($parentTable)->getClassname() . "::create()->findPk(\$this->getPrimaryKey(), \$con);
}
}
";
}
protected function addObjectGetSyncParent(&$script)
{
$parentTable = $this->getParentTable();
$pkeys = $parentTable->getPrimaryKey();
$cptype = $pkeys[0]->getPhpType();
$script .= "
/**
* Create or Update the parent " . $parentTable->getPhpName() . " object
* And return its primary key
*
* @return " . $cptype . " The primary key of the parent object
*/
public function getSyncParent(\$con = null)
{
\$parent = \$this->getParentOrCreate(\$con);";
foreach ($parentTable->getColumns() as $column) {
if ($column->isPrimaryKey() || $column->getName() == $this->getParameter('descendant_column')) {
continue;
}
$phpName = $column->getPhpName();
$script .= "
\$parent->set{$phpName}(\$this->get{$phpName}());";
}
foreach ($parentTable->getForeignKeys() as $fk) {
if (isset($fk->isParentChild) && $fk->isParentChild) {
continue;
}
$refPhpName = $this->builder->getFKPhpNameAffix($fk, $plural = false);
$script .= "
if (\$this->get" . $refPhpName . "() && \$this->get" . $refPhpName . "()->isNew()) {
\$parent->set" . $refPhpName . "(\$this->get" . $refPhpName . "());
}";
}
$script .= "
return \$parent;
}
";
}
}

View file

@ -0,0 +1,89 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Gives a model class the ability to remain in database even when the user deletes object
* Uses an additional column storing the deletion date
* And an additional condition for every read query to only consider rows with no deletion date
*
* @author François Zaninotto
* @version $Revision: 1612 $
* @package propel.generator.behavior.concrete_inheritance
*/
class ConcreteInheritanceParentBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'descendant_column' => 'descendant_class'
);
public function modifyTable()
{
$table = $this->getTable();
if (!$table->containsColumn($this->getParameter('descendant_column'))) {
$table->addColumn(array(
'name' => $this->getParameter('descendant_column'),
'type' => 'VARCHAR',
'size' => 100
));
}
}
protected function getColumnGetter()
{
return 'get' . $this->getColumnForParameter('descendant_column')->getPhpName();
}
public function objectMethods($builder)
{
$this->builder = $builder;
$script .= '';
$this->addHasChildObject($script);
$this->addGetChildObject($script);
return $script;
}
protected function addHasChildObject(&$script)
{
$script .= "
/**
* Whether or not this object is the parent of a child object
*
* @return bool
*/
public function hasChildObject()
{
return \$this->" . $this->getColumnGetter() . "() !== null;
}
";
}
protected function addGetChildObject(&$script)
{
$script .= "
/**
* Get the child object of this object
*
* @return mixed
*/
public function getChildObject()
{
if (!\$this->hasChildObject()) {
return null;
}
\$childObjectClass = \$this->" . $this->getColumnGetter() . "();
\$childObject = PropelQuery::from(\$childObjectClass)->findPk(\$this->getPrimaryKey());
return \$childObject->hasChildObject() ? \$childObject->getChildObject() : \$childObject;
}
";
}
}

View file

@ -0,0 +1,99 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once dirname(__FILE__) . '/NestedSetBehaviorObjectBuilderModifier.php';
require_once dirname(__FILE__) . '/NestedSetBehaviorQueryBuilderModifier.php';
require_once dirname(__FILE__) . '/NestedSetBehaviorPeerBuilderModifier.php';
/**
* Behavior to adds nested set tree structure columns and abilities
*
* @author François Zaninotto
* @package propel.generator.behavior.nestedset
*/
class NestedSetBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'left_column' => 'tree_left',
'right_column' => 'tree_right',
'level_column' => 'tree_level',
'use_scope' => 'false',
'scope_column' => 'tree_scope',
'method_proxies' => 'false'
);
protected $objectBuilderModifier, $queryBuilderModifier, $peerBuilderModifier;
/**
* Add the left, right and scope to the current table
*/
public function modifyTable()
{
if(!$this->getTable()->containsColumn($this->getParameter('left_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('left_column'),
'type' => 'INTEGER'
));
}
if(!$this->getTable()->containsColumn($this->getParameter('right_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('right_column'),
'type' => 'INTEGER'
));
}
if(!$this->getTable()->containsColumn($this->getParameter('level_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('level_column'),
'type' => 'INTEGER'
));
}
if ($this->getParameter('use_scope') == 'true' &&
!$this->getTable()->containsColumn($this->getParameter('scope_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('scope_column'),
'type' => 'INTEGER'
));
}
}
public function getObjectBuilderModifier()
{
if (is_null($this->objectBuilderModifier))
{
$this->objectBuilderModifier = new NestedSetBehaviorObjectBuilderModifier($this);
}
return $this->objectBuilderModifier;
}
public function getQueryBuilderModifier()
{
if (is_null($this->queryBuilderModifier))
{
$this->queryBuilderModifier = new NestedSetBehaviorQueryBuilderModifier($this);
}
return $this->queryBuilderModifier;
}
public function getPeerBuilderModifier()
{
if (is_null($this->peerBuilderModifier))
{
$this->peerBuilderModifier = new NestedSetBehaviorPeerBuilderModifier($this);
}
return $this->peerBuilderModifier;
}
public function useScope()
{
return $this->getParameter('use_scope') == 'true';
}
}

View file

@ -0,0 +1,555 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Behavior to adds nested set tree structure columns and abilities
*
* @author François Zaninotto
* @author heltem <heltem@o2php.com>
* @package propel.generator.behavior.nestedset
*/
class NestedSetBehaviorPeerBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
public function __construct($behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
}
protected function getParameter($key)
{
return $this->behavior->getParameter($key);
}
protected function getColumn($name)
{
return $this->behavior->getColumnForParameter($name);
}
protected function getColumnAttribute($name)
{
return strtolower($this->getColumn($name)->getName());
}
protected function getColumnConstant($name)
{
return strtoupper($this->getColumn($name)->getName());
}
protected function getColumnPhpName($name)
{
return $this->getColumn($name)->getPhpName();
}
protected function setBuilder($builder)
{
$this->builder = $builder;
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
}
public function staticAttributes($builder)
{
$tableName = $this->table->getName();
$script = "
/**
* Left column for the set
*/
const LEFT_COL = '" . $tableName . '.' . $this->getColumnConstant('left_column') . "';
/**
* Right column for the set
*/
const RIGHT_COL = '" . $tableName . '.' . $this->getColumnConstant('right_column') . "';
/**
* Level column for the set
*/
const LEVEL_COL = '" . $tableName . '.' . $this->getColumnConstant('level_column') . "';
";
if ($this->behavior->useScope()) {
$script .= "
/**
* Scope column for the set
*/
const SCOPE_COL = '" . $tableName . '.' . $this->getColumnConstant('scope_column') . "';
";
}
return $script;
}
public function staticMethods($builder)
{
$this->setBuilder($builder);
$script = '';
if ($this->getParameter('use_scope') == 'true')
{
$this->addRetrieveRoots($script);
}
$this->addRetrieveRoot($script);
$this->addRetrieveTree($script);
$this->addIsValid($script);
$this->addDeleteTree($script);
$this->addShiftRLValues($script);
$this->addShiftLevel($script);
$this->addUpdateLoadedNodes($script);
$this->addMakeRoomForLeaf($script);
$this->addFixLevels($script);
return $script;
}
protected function addRetrieveRoots(&$script)
{
$peerClassname = $this->peerClassname;
$script .= "
/**
* Returns the root nodes for the tree
*
* @param PropelPDO \$con Connection to use.
* @return {$this->objectClassname} Propel object for root node
*/
public static function retrieveRoots(Criteria \$criteria = null, PropelPDO \$con = null)
{
if (\$criteria === null) {
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
}
\$criteria->add($peerClassname::LEFT_COL, 1, Criteria::EQUAL);
return $peerClassname::doSelect(\$criteria, \$con);
}
";
}
protected function addRetrieveRoot(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Returns the root node for a given scope
*";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which root node to return";
}
$script .= "
* @param PropelPDO \$con Connection to use.
* @return {$this->objectClassname} Propel object for root node
*/
public static function retrieveRoot(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{
\$c = new Criteria($peerClassname::DATABASE_NAME);
\$c->add($peerClassname::LEFT_COL, 1, Criteria::EQUAL);";
if($useScope) {
$script .= "
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
return $peerClassname::doSelectOne(\$c, \$con);
}
";
}
protected function addRetrieveTree(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Returns the whole tree node for a given scope
*";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which root node to return";
}
$script .= "
* @param Criteria \$criteria Optional Criteria to filter the query
* @param PropelPDO \$con Connection to use.
* @return {$this->objectClassname} Propel object for root node
*/
public static function retrieveTree(" . ($useScope ? "\$scope = null, " : "") . "Criteria \$criteria = null, PropelPDO \$con = null)
{
if (\$criteria === null) {
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
}
\$criteria->addAscendingOrderByColumn($peerClassname::LEFT_COL);";
if($useScope) {
$script .= "
\$criteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
return $peerClassname::doSelect(\$criteria, \$con);
}
";
}
protected function addIsValid(&$script)
{
$objectClassname = $this->objectClassname;
$script .= "
/**
* Tests if node is valid
*
* @param $objectClassname \$node Propel object for src node
* @return bool
*/
public static function isValid($objectClassname \$node = null)
{
if (is_object(\$node) && \$node->getRightValue() > \$node->getLeftValue()) {
return true;
} else {
return false;
}
}
";
}
protected function addDeleteTree(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Delete an entire tree
* ";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which tree to delete";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*
* @return int The number of deleted nodes
*/
public static function deleteTree(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{";
if($useScope) {
$script .= "
\$c = new Criteria($peerClassname::DATABASE_NAME);
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);
return $peerClassname::doDelete(\$c, \$con);";
} else {
$script .= "
return $peerClassname::doDeleteAll(\$con);";
}
$script .= "
}
";
}
protected function addShiftRLValues(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Adds \$delta to all L and R values that are >= \$first and <= \$last.
* '\$delta' can also be negative.
*
* @param int \$delta Value to be shifted by, can be negative
* @param int \$first First node to be shifted
* @param int \$last Last node to be shifted (optional)";
if($useScope) {
$script .= "
* @param int \$scope Scope to use for the shift";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*/
public static function shiftRLValues(\$delta, \$first, \$last = null" . ($useScope ? ", \$scope = null" : ""). ", PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
}
// Shift left column values
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$criterion = \$whereCriteria->getNewCriterion($peerClassname::LEFT_COL, \$first, Criteria::GREATER_EQUAL);
if (null !== \$last) {
\$criterion->addAnd(\$whereCriteria->getNewCriterion($peerClassname::LEFT_COL, \$last, Criteria::LESS_EQUAL));
}
\$whereCriteria->add(\$criterion);";
if ($useScope) {
$script .= "
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$valuesCriteria->add($peerClassname::LEFT_COL, array('raw' => $peerClassname::LEFT_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
{$this->builder->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
// Shift right column values
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$criterion = \$whereCriteria->getNewCriterion($peerClassname::RIGHT_COL, \$first, Criteria::GREATER_EQUAL);
if (null !== \$last) {
\$criterion->addAnd(\$whereCriteria->getNewCriterion($peerClassname::RIGHT_COL, \$last, Criteria::LESS_EQUAL));
}
\$whereCriteria->add(\$criterion);";
if ($useScope) {
$script .= "
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$valuesCriteria->add($peerClassname::RIGHT_COL, array('raw' => $peerClassname::RIGHT_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
{$this->builder->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
}
";
}
protected function addShiftLevel(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Adds \$delta to level for nodes having left value >= \$first and right value <= \$last.
* '\$delta' can also be negative.
*
* @param int \$delta Value to be shifted by, can be negative
* @param int \$first First node to be shifted
* @param int \$last Last node to be shifted";
if($useScope) {
$script .= "
* @param int \$scope Scope to use for the shift";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*/
public static function shiftLevel(\$delta, \$first, \$last" . ($useScope ? ", \$scope = null" : ""). ", PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
}
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$whereCriteria->add($peerClassname::LEFT_COL, \$first, Criteria::GREATER_EQUAL);
\$whereCriteria->add($peerClassname::RIGHT_COL, \$last, Criteria::LESS_EQUAL);";
if ($useScope) {
$script .= "
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$valuesCriteria->add($peerClassname::LEVEL_COL, array('raw' => $peerClassname::LEVEL_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
{$this->builder->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
}
";
}
protected function addUpdateLoadedNodes(&$script)
{
$peerClassname = $this->peerClassname;
$script .= "
/**
* Reload all already loaded nodes to sync them with updated db
*
* @param PropelPDO \$con Connection to use.
*/
public static function updateLoadedNodes(PropelPDO \$con = null)
{
if (Propel::isInstancePoolingEnabled()) {
\$keys = array();
foreach ($peerClassname::\$instances as \$obj) {
\$keys[] = \$obj->getPrimaryKey();
}
if (!empty(\$keys)) {
// We don't need to alter the object instance pool; we're just modifying these ones
// already in the pool.
\$criteria = new Criteria($peerClassname::DATABASE_NAME);";
if (count($this->table->getPrimaryKey()) === 1) {
$pkey = $this->table->getPrimaryKey();
$col = array_shift($pkey);
$script .= "
\$criteria->add(".$this->builder->getColumnConstant($col).", \$keys, Criteria::IN);
";
} else {
$fields = array();
foreach ($this->table->getPrimaryKey() as $k => $col) {
$fields[] = $this->builder->getColumnConstant($col);
};
$script .= "
// Loop on each instances in pool
foreach (\$keys as \$values) {
// Create initial Criterion
\$cton = \$criteria->getNewCriterion(" . $fields[0] . ", \$values[0]);";
unset($fields[0]);
foreach ($fields as $k => $col) {
$script .= "
// Create next criterion
\$nextcton = \$criteria->getNewCriterion(" . $col . ", \$values[$k]);
// And merge it with the first
\$cton->addAnd(\$nextcton);";
}
$script .= "
// Add final Criterion to Criteria
\$criteria->addOr(\$cton);
}";
}
$script .= "
\$stmt = $peerClassname::doSelectStmt(\$criteria, \$con);
while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
\$key = $peerClassname::getPrimaryKeyHashFromRow(\$row, 0);
if (null !== (\$object = $peerClassname::getInstanceFromPool(\$key))) {";
$n = 0;
foreach ($this->table->getColumns() as $col) {
if ($col->getPhpName() == $this->getColumnPhpName('left_column')) {
$script .= "
\$object->setLeftValue(\$row[$n]);";
} else if ($col->getPhpName() == $this->getColumnPhpName('right_column')) {
$script .= "
\$object->setRightValue(\$row[$n]);";
} else if ($col->getPhpName() == $this->getColumnPhpName('level_column')) {
$script .= "
\$object->setLevel(\$row[$n]);
\$object->clearNestedSetChildren();";
}
$n++;
}
$script .= "
}
}
\$stmt->closeCursor();
}
}
}
";
}
protected function addMakeRoomForLeaf(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Update the tree to allow insertion of a leaf at the specified position
*
* @param int \$left left column value";
if ($useScope) {
$script .= "
* @param integer \$scope scope column value";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*/
public static function makeRoomForLeaf(\$left" . ($useScope ? ", \$scope" : ""). ", PropelPDO \$con = null)
{
// Update database nodes
$peerClassname::shiftRLValues(2, \$left, null" . ($useScope ? ", \$scope" : "") . ", \$con);
// Update all loaded nodes
$peerClassname::updateLoadedNodes(\$con);
}
";
}
protected function addFixLevels(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Update the tree to allow insertion of a leaf at the specified position
*";
if ($useScope) {
$script .= "
* @param integer \$scope scope column value";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*/
public static function fixLevels(" . ($useScope ? "\$scope, " : ""). "PropelPDO \$con = null)
{
\$c = new Criteria();";
if ($useScope) {
$script .= "
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$c->addAscendingOrderByColumn($peerClassname::LEFT_COL);
\$stmt = $peerClassname::doSelectStmt(\$c, \$con);
";
if (!$this->table->getChildrenColumn()) {
$script .= "
// set the class once to avoid overhead in the loop
\$cls = $peerClassname::getOMClass(false);";
}
$script .= "
\$level = null;
// iterate over the statement
while (\$row = \$stmt->fetch(PDO::FETCH_NUM)) {
// hydrate object
\$key = $peerClassname::getPrimaryKeyHashFromRow(\$row, 0);
if (null === (\$obj = $peerClassname::getInstanceFromPool(\$key))) {";
if ($this->table->getChildrenColumn()) {
$script .= "
// class must be set each time from the record row
\$cls = $peerClassname::getOMClass(\$row, 0);
\$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
" . $this->builder->buildObjectInstanceCreationCode('$obj', '$cls') . "
\$obj->hydrate(\$row);
$peerClassname::addInstanceToPool(\$obj, \$key);";
} else {
$script .= "
" . $this->builder->buildObjectInstanceCreationCode('$obj', '$cls') . "
\$obj->hydrate(\$row);
$peerClassname::addInstanceToPool(\$obj, \$key);";
}
$script .= "
}
// compute level
// Algorithm shamelessly stolen from sfPropelActAsNestedSetBehaviorPlugin
// Probably authored by Tristan Rivoallan
if (\$level === null) {
\$level = 0;
\$i = 0;
\$prev = array(\$obj->getRightValue());
} else {
while (\$obj->getRightValue() > \$prev[\$i]) {
\$i--;
}
\$level = ++\$i;
\$prev[\$i] = \$obj->getRightValue();
}
// update level in node if necessary
if (\$obj->getLevel() !== \$level) {
\$obj->setLevel(\$level);
\$obj->save(\$con);
}
}
\$stmt->closeCursor();
}
";
}
}

View file

@ -0,0 +1,357 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Behavior to adds nested set tree structure columns and abilities
*
* @author François Zaninotto
* @package propel.generator.behavior.nestedset
*/
class NestedSetBehaviorQueryBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
public function __construct($behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
}
protected function getParameter($key)
{
return $this->behavior->getParameter($key);
}
protected function getColumn($name)
{
return $this->behavior->getColumnForParameter($name);
}
protected function setBuilder($builder)
{
$this->builder = $builder;
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
$this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
}
public function queryMethods($builder)
{
$this->setBuilder($builder);
$script = '';
// select filters
if ($this->behavior->useScope()) {
$this->addTreeRoots($script);
$this->addInTree($script);
}
$this->addDescendantsOf($script);
$this->addBranchOf($script);
$this->addChildrenOf($script);
$this->addSiblingsOf($script);
$this->addAncestorsOf($script);
$this->addRootsOf($script);
// select orders
$this->addOrderByBranch($script);
$this->addOrderByLevel($script);
// select termination methods
$this->addFindRoot($script);
$this->addFindTree($script);
return $script;
}
protected function addTreeRoots(&$script)
{
$script .= "
/**
* Filter the query to restrict the result to root objects
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function treeRoots()
{
return \$this->addUsingAlias({$this->peerClassname}::LEFT_COL, 1, Criteria::EQUAL);
}
";
}
protected function addInTree(&$script)
{
$script .= "
/**
* Returns the objects in a certain tree, from the tree scope
*
* @param int \$scope Scope to determine which objects node to return
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function inTree(\$scope = null)
{
return \$this->addUsingAlias({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);
}
";
}
protected function addDescendantsOf(&$script)
{
$objectName = '$' . $this->table->getStudlyPhpName();
$script .= "
/**
* Filter the query to restrict the result to descendants of an object
*
* @param {$this->objectClassname} $objectName The object to use for descendant search
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function descendantsOf($objectName)
{
return \$this";
if ($this->behavior->useScope()) {
$script .= "
->inTree({$objectName}->getScopeValue())";
}
$script .= "
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::GREATER_THAN)
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::LESS_THAN);
}
";
}
protected function addBranchOf(&$script)
{
$objectName = '$' . $this->table->getStudlyPhpName();
$script .= "
/**
* Filter the query to restrict the result to the branch of an object.
* Same as descendantsOf(), except that it includes the object passed as parameter in the result
*
* @param {$this->objectClassname} $objectName The object to use for branch search
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function branchOf($objectName)
{
return \$this";
if ($this->behavior->useScope()) {
$script .= "
->inTree({$objectName}->getScopeValue())";
}
$script .= "
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::GREATER_EQUAL)
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::LESS_EQUAL);
}
";
}
protected function addChildrenOf(&$script)
{
$objectName = '$' . $this->table->getStudlyPhpName();
$script .= "
/**
* Filter the query to restrict the result to children of an object
*
* @param {$this->objectClassname} $objectName The object to use for child search
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function childrenOf($objectName)
{
return \$this
->descendantsOf($objectName)
->addUsingAlias({$this->peerClassname}::LEVEL_COL, {$objectName}->getLevel() + 1, Criteria::EQUAL);
}
";
}
protected function addSiblingsOf(&$script)
{
$objectName = '$' . $this->table->getStudlyPhpName();
$script .= "
/**
* Filter the query to restrict the result to siblings of an object.
* The result does not include the object passed as parameter.
*
* @param {$this->objectClassname} $objectName The object to use for sibling search
* @param PropelPDO \$con Connection to use.
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function siblingsOf($objectName, PropelPDO \$con = null)
{
if ({$objectName}->isRoot()) {
return \$this->
add({$this->peerClassname}::LEVEL_COL, '1<>1', Criteria::CUSTOM);
} else {
return \$this
->childrenOf({$objectName}->getParent(\$con))
->prune($objectName);
}
}
";
}
protected function addAncestorsOf(&$script)
{
$objectName = '$' . $this->table->getStudlyPhpName();
$script .= "
/**
* Filter the query to restrict the result to ancestors of an object
*
* @param {$this->objectClassname} $objectName The object to use for ancestors search
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function ancestorsOf($objectName)
{
return \$this";
if ($this->behavior->useScope()) {
$script .= "
->inTree({$objectName}->getScopeValue())";
}
$script .= "
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::LESS_THAN)
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::GREATER_THAN);
}
";
}
protected function addRootsOf(&$script)
{
$objectName = '$' . $this->table->getStudlyPhpName();
$script .= "
/**
* Filter the query to restrict the result to roots of an object.
* Same as ancestorsOf(), except that it includes the object passed as parameter in the result
*
* @param {$this->objectClassname} $objectName The object to use for roots search
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function rootsOf($objectName)
{
return \$this";
if ($this->behavior->useScope()) {
$script .= "
->inTree({$objectName}->getScopeValue())";
}
$script .= "
->addUsingAlias({$this->peerClassname}::LEFT_COL, {$objectName}->getLeftValue(), Criteria::LESS_EQUAL)
->addUsingAlias({$this->peerClassname}::RIGHT_COL, {$objectName}->getRightValue(), Criteria::GREATER_EQUAL);
}
";
}
protected function addOrderByBranch(&$script)
{
$script .= "
/**
* Order the result by branch, i.e. natural tree order
*
* @param bool \$reverse if true, reverses the order
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function orderByBranch(\$reverse = false)
{
if (\$reverse) {
return \$this
->addDescendingOrderByColumn({$this->peerClassname}::LEFT_COL);
} else {
return \$this
->addAscendingOrderByColumn({$this->peerClassname}::LEFT_COL);
}
}
";
}
protected function addOrderByLevel(&$script)
{
$script .= "
/**
* Order the result by level, the closer to the root first
*
* @param bool \$reverse if true, reverses the order
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function orderByLevel(\$reverse = false)
{
if (\$reverse) {
return \$this
->addAscendingOrderByColumn({$this->peerClassname}::RIGHT_COL);
} else {
return \$this
->addDescendingOrderByColumn({$this->peerClassname}::RIGHT_COL);
}
}
";
}
protected function addFindRoot(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Returns " . ($useScope ? 'a' : 'the') ." root node for the tree
*";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which root node to return";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*
* @return {$this->objectClassname} The tree root object
*/
public function findRoot(" . ($useScope ? "\$scope = null, " : "") . "\$con = null)
{
return \$this
->addUsingAlias({$this->peerClassname}::LEFT_COL, 1, Criteria::EQUAL)";
if ($useScope) {
$script .= "
->inTree(\$scope)";
}
$script .= "
->findOne(\$con);
}
";
}
protected function addFindTree(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Returns " . ($useScope ? 'a' : 'the') ." tree of objects
*";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which tree node to return";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*
* @return mixed the list of results, formatted by the current formatter
*/
public function findTree(" . ($useScope ? "\$scope = null, " : "") . "\$con = null)
{
return \$this";
if ($useScope) {
$script .= "
->inTree(\$scope)";
}
$script .= "
->orderByBranch()
->find(\$con);
}
";
}
}

View file

@ -0,0 +1,262 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Speeds up queries on a model by caching the query
*
* @author François Zaninotto
* @version $Revision: 1746 $
* @package propel.generator.behavior.cacheable
*/
class QueryCacheBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'backend' => 'apc',
'lifetime' => 3600,
);
public function queryAttributes($builder)
{
$script = "protected \$queryKey = '';
";
switch ($this->getParameter('backend')) {
case 'backend':
$script .= "protected static \$cacheBackend = array();
";
break;
case 'apc':
break;
case 'custom':
default:
$script .= "protected static \$cacheBackend;
";
break;
}
return $script;
}
public function queryMethods($builder)
{
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
$script = '';
$this->addSetQueryKey($script);
$this->addGetQueryKey($script);
$this->addCacheContains($script);
$this->addCacheFetch($script);
$this->addCacheStore($script);
$this->addGetSelectStatement($script);
$this->addGetCountStatement($script);
return $script;
}
protected function addSetQueryKey(&$script)
{
$script .= "
public function setQueryKey(\$key)
{
\$this->queryKey = \$key;
return \$this;
}
";
}
protected function addGetQueryKey(&$script)
{
$script .= "
public function getQueryKey()
{
return \$this->queryKey;
}
";
}
protected function addCacheContains(&$script)
{
$script .= "
public function cacheContains(\$key)
{";
switch ($this->getParameter('backend')) {
case 'apc':
$script .= "
return apc_fetch(\$key);";
break;
case 'array':
$script .= "
return isset(self::\$cacheBackend[\$key]);";
break;
case 'custom':
default:
$script .= "
throw new PropelException('You must override the cacheContains(), cacheStore(), and cacheFetch() methods to enable query cache');";
break;
}
$script .= "
}
";
}
protected function addCacheStore(&$script)
{
$script .= "
public function cacheStore(\$key, \$value, \$lifetime = " .$this->getParameter('lifetime') . ")
{";
switch ($this->getParameter('backend')) {
case 'apc':
$script .= "
apc_store(\$key, \$value, \$lifetime);";
break;
case 'array':
$script .= "
self::\$cacheBackend[\$key] = \$value;";
break;
case 'custom':
default:
$script .= "
throw new PropelException('You must override the cacheContains(), cacheStore(), and cacheFetch() methods to enable query cache');";
break;
}
$script .= "
}
";
}
protected function addCacheFetch(&$script)
{
$script .= "
public function cacheFetch(\$key)
{";
switch ($this->getParameter('backend')) {
case 'apc':
$script .= "
return apc_fetch(\$key);";
break;
case 'array':
$script .= "
return isset(self::\$cacheBackend[\$key]) ? self::\$cacheBackend[\$key] : null;";
break;
case 'custom':
default:
$script .= "
throw new PropelException('You must override the cacheContains(), cacheStore(), and cacheFetch() methods to enable query cache');";
break;
}
$script .= "
}
";
}
protected function addGetSelectStatement(&$script)
{
$script .= "
protected function getSelectStatement(\$con = null)
{
\$dbMap = Propel::getDatabaseMap(" . $this->peerClassname ."::DATABASE_NAME);
\$db = Propel::getDB(" . $this->peerClassname ."::DATABASE_NAME);
if (\$con === null) {
\$con = Propel::getConnection(" . $this->peerClassname ."::DATABASE_NAME, Propel::CONNECTION_READ);
}
if (!\$this->hasSelectClause()) {
\$this->addSelfSelectColumns();
}
\$con->beginTransaction();
try {
\$this->basePreSelect(\$con);
\$key = \$this->getQueryKey();
if (\$key && \$this->cacheContains(\$key)) {
\$params = \$this->getParams();
\$sql = \$this->cacheFetch(\$key);
} else {
\$params = array();
\$sql = BasePeer::createSelectSql(\$this, \$params);
if (\$key) {
\$this->cacheStore(\$key, \$sql);
}
}
\$stmt = \$con->prepare(\$sql);
BasePeer::populateStmtValues(\$stmt, \$params, \$dbMap, \$db);
\$stmt->execute();
\$con->commit();
} catch (PropelException \$e) {
\$con->rollback();
throw \$e;
}
return \$stmt;
}
";
}
protected function addGetCountStatement(&$script)
{
$script .= "
protected function getCountStatement(\$con = null)
{
\$dbMap = Propel::getDatabaseMap(\$this->getDbName());
\$db = Propel::getDB(\$this->getDbName());
if (\$con === null) {
\$con = Propel::getConnection(\$this->getDbName(), Propel::CONNECTION_READ);
}
\$con->beginTransaction();
try {
\$this->basePreSelect(\$con);
\$key = \$this->getQueryKey();
if (\$key && \$this->cacheContains(\$key)) {
\$params = \$this->getParams();
\$sql = \$this->cacheFetch(\$key);
} else {
if (!\$this->hasSelectClause() && !\$this->getPrimaryCriteria()) {
\$this->addSelfSelectColumns();
}
\$params = array();
\$needsComplexCount = \$this->getGroupByColumns()
|| \$this->getOffset()
|| \$this->getLimit()
|| \$this->getHaving()
|| in_array(Criteria::DISTINCT, \$this->getSelectModifiers());
if (\$needsComplexCount) {
if (BasePeer::needsSelectAliases(\$this)) {
if (\$this->getHaving()) {
throw new PropelException('Propel cannot create a COUNT query when using HAVING and duplicate column names in the SELECT part');
}
BasePeer::turnSelectColumnsToAliases(\$this);
}
\$selectSql = BasePeer::createSelectSql(\$this, \$params);
\$sql = 'SELECT COUNT(*) FROM (' . \$selectSql . ') propelmatch4cnt';
} else {
// Replace SELECT columns with COUNT(*)
\$this->clearSelectColumns()->addSelectColumn('COUNT(*)');
\$sql = BasePeer::createSelectSql(\$this, \$params);
}
if (\$key) {
\$this->cacheStore(\$key, \$sql);
}
}
\$stmt = \$con->prepare(\$sql);
BasePeer::populateStmtValues(\$stmt, \$params, \$dbMap, \$db);
\$stmt->execute();
\$con->commit();
} catch (PropelException \$e) {
\$con->rollback();
throw \$e;
}
return \$stmt;
}
";
}
}

View file

@ -0,0 +1,332 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Adds a slug column
*
* @author Francois Zaninotto
* @author Massimiliano Arione
* @version $Revision: 1629 $
* @package propel.generator.behavior.sluggable
*/
class SluggableBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'slug_column' => 'slug',
'slug_pattern' => '',
'replace_pattern' => '/\W+/', // Tip: use '/[^\\pL\\d]+/u' instead if you're in PHP5.3
'replacement' => '-',
'separator' => '-',
'permanent' => 'false'
);
/**
* Add the slug_column to the current table
*/
public function modifyTable()
{
if(!$this->getTable()->containsColumn($this->getParameter('slug_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('slug_column'),
'type' => 'VARCHAR',
'size' => 255
));
// add a unique to column
$unique = new Unique($this->getColumnForParameter('slug_column'));
$unique->setName($this->getTable()->getName() . '_slug');
$unique->addColumn($this->getTable()->getColumn($this->getParameter('slug_column')));
$this->getTable()->addUnique($unique);
}
}
/**
* Get the getter of the column of the behavior
*
* @return string The related getter, e.g. 'getSlug'
*/
protected function getColumnGetter()
{
return 'get' . $this->getColumnForParameter('slug_column')->getPhpName();
}
/**
* Get the setter of the column of the behavior
*
* @return string The related setter, e.g. 'setSlug'
*/
protected function getColumnSetter()
{
return 'set' . $this->getColumnForParameter('slug_column')->getPhpName();
}
/**
* Add code in ObjectBuilder::preSave
*
* @return string The code to put at the hook
*/
public function preSave($builder)
{
$const = $builder->getColumnConstant($this->getColumnForParameter('slug_column'), $this->getTable()->getPhpName() . 'Peer');
$script = "
if (\$this->isColumnModified($const) && \$this->{$this->getColumnGetter()}()) {
\$this->{$this->getColumnSetter()}(\$this->makeSlugUnique(\$this->{$this->getColumnGetter()}()));";
if ($this->getParameter('permanent') == 'true') {
$script .= "
} elseif (!\$this->{$this->getColumnGetter()}()) {
\$this->{$this->getColumnSetter()}(\$this->createSlug());
}";
} else {
$script .= "
} else {
\$this->{$this->getColumnSetter()}(\$this->createSlug());
}";
}
return $script;
}
public function objectMethods($builder)
{
$this->builder = $builder;
$script = '';
if ($this->getParameter('slug_column') != 'slug') {
$this->addSlugSetter($script);
$this->addSlugGetter($script);
}
$this->addCreateSlug($script);
$this->addCreateRawSlug($script);
$this->addCleanupSlugPart($script);
$this->addLimitSlugSize($script);
$this->addMakeSlugUnique($script);
return $script;
}
protected function addSlugSetter(&$script)
{
$script .= "
/**
* Wrap the setter for slug value
*
* @param string
* @return " . $this->getTable()->getPhpName() . "
*/
public function setSlug(\$v)
{
return \$this->" . $this->getColumnSetter() . "(\$v);
}
";
}
protected function addSlugGetter(&$script)
{
$script .= "
/**
* Wrap the getter for slug value
*
* @return string
*/
public function getSlug()
{
return \$this->" . $this->getColumnGetter() . "();
}
";
}
protected function addCreateSlug(&$script)
{
$script .= "
/**
* Create a unique slug based on the object
*
* @return string The object slug
*/
protected function createSlug()
{
\$slug = \$this->createRawSlug();
\$slug = \$this->limitSlugSize(\$slug);
\$slug = \$this->makeSlugUnique(\$slug);
return \$slug;
}
";
}
protected function addCreateRawSlug(&$script)
{
$pattern = $this->getParameter('slug_pattern');
$script .= "
/**
* Create the slug from the appropriate columns
*
* @return string
*/
protected function createRawSlug()
{
";
if ($pattern) {
$script .= "return '" . str_replace(array('{', '}'), array('\' . $this->cleanupSlugPart($this->get', '()) . \''), $pattern). "';";
} else {
$script .= "return \$this->cleanupSlugPart(\$this->__toString());";
}
$script .= "
}
";
return $script;
}
public function addCleanupSlugPart(&$script)
{
$script .= "
/**
* Cleanup a string to make a slug of it
* Removes special characters, replaces blanks with a separator, and trim it
*
* @param string \$text the text to slugify
* @param string \$separator the separator used by slug
* @return string the slugified text
*/
protected static function cleanupSlugPart(\$slug, \$replacement = '" . $this->getParameter('replacement') . "')
{
// transliterate
if (function_exists('iconv')) {
\$slug = iconv('utf-8', 'us-ascii//TRANSLIT', \$slug);
}
// lowercase
if (function_exists('mb_strtolower')) {
\$slug = mb_strtolower(\$slug);
} else {
\$slug = strtolower(\$slug);
}
// remove accents resulting from OSX's iconv
\$slug = str_replace(array('\'', '`', '^'), '', \$slug);
// replace non letter or digits with separator
\$slug = preg_replace('" . $this->getParameter('replace_pattern') . "', \$replacement, \$slug);
// trim
\$slug = trim(\$slug, \$replacement);
if (empty(\$slug)) {
return 'n-a';
}
return \$slug;
}
";
}
public function addLimitSlugSize(&$script)
{
$size = $this->getColumnForParameter('slug_column')->getSize();
$script .= "
/**
* Make sure the slug is short enough to accomodate the column size
*
* @param string \$slug the slug to check
*
* @return string the truncated slug
*/
protected static function limitSlugSize(\$slug, \$incrementReservedSpace = 3)
{
// check length, as suffix could put it over maximum
if (strlen(\$slug) > ($size - \$incrementReservedSpace)) {
\$slug = substr(\$slug, 0, $size - \$incrementReservedSpace);
}
return \$slug;
}
";
}
public function addMakeSlugUnique(&$script)
{
$script .= "
/**
* Get the slug, ensuring its uniqueness
*
* @param string \$slug the slug to check
* @param string \$separator the separator used by slug
* @return string the unique slug
*/
protected function makeSlugUnique(\$slug, \$separator = '" . $this->getParameter('separator') ."', \$increment = 0)
{
\$slug2 = empty(\$increment) ? \$slug : \$slug . \$separator . \$increment;
\$slugAlreadyExists = " . $this->builder->getStubQueryBuilder()->getClassname() . "::create()
->filterBySlug(\$slug2)
->prune(\$this)";
// watch out: some of the columns may be hidden by the soft_delete behavior
if ($this->table->hasBehavior('soft_delete')) {
$script .= "
->includeDeleted()";
}
$script .= "
->count();
if (\$slugAlreadyExists) {
return \$this->makeSlugUnique(\$slug, \$separator, ++\$increment);
} else {
return \$slug2;
}
}
";
}
public function queryMethods($builder)
{
$this->builder = $builder;
$script = '';
if ($this->getParameter('slug_column') != 'slug') {
$this->addFilterBySlug($script);
}
$this->addFindOneBySlug($script);
return $script;
}
protected function addFilterBySlug(&$script)
{
$script .= "
/**
* Filter the query on the slug column
*
* @param string \$slug The value to use as filter.
*
* @return " . $this->builder->getStubQueryBuilder()->getClassname() . " The current query, for fluid interface
*/
public function filterBySlug(\$slug)
{
return \$this->addUsingAlias(" . $this->builder->getColumnConstant($this->getColumnForParameter('slug_column')) . ", \$slug, Criteria::EQUAL);
}
";
}
protected function addFindOneBySlug(&$script)
{
$script .= "
/**
* Find one object based on its slug
*
* @param string \$slug The value to use as filter.
* @param PropelPDO \$con The optional connection object
*
* @return " . $this->builder->getStubObjectBuilder()->getClassname() . " the result, formatted by the current formatter
*/
public function findOneBySlug(\$slug, \$con = null)
{
return \$this->filterBySlug(\$slug)->findOne(\$con);
}
";
}
}

View file

@ -0,0 +1,83 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once dirname(__FILE__) . '/SortableBehaviorObjectBuilderModifier.php';
require_once dirname(__FILE__) . '/SortableBehaviorQueryBuilderModifier.php';
require_once dirname(__FILE__) . '/SortableBehaviorPeerBuilderModifier.php';
/**
* Gives a model class the ability to be ordered
* Uses one additional column storing the rank
*
* @author Massimiliano Arione
* @version $Revision: 1612 $
* @package propel.generator.behavior.sortable
*/
class SortableBehavior extends Behavior
{
// default parameters value
protected $parameters = array(
'rank_column' => 'sortable_rank',
'use_scope' => 'false',
'scope_column' => 'sortable_scope',
);
protected $objectBuilderModifier, $queryBuilderModifier, $peerBuilderModifier;
/**
* Add the rank_column to the current table
*/
public function modifyTable()
{
if (!$this->getTable()->containsColumn($this->getParameter('rank_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('rank_column'),
'type' => 'INTEGER'
));
}
if ($this->getParameter('use_scope') == 'true' &&
!$this->getTable()->containsColumn($this->getParameter('scope_column'))) {
$this->getTable()->addColumn(array(
'name' => $this->getParameter('scope_column'),
'type' => 'INTEGER'
));
}
}
public function getObjectBuilderModifier()
{
if (is_null($this->objectBuilderModifier)) {
$this->objectBuilderModifier = new SortableBehaviorObjectBuilderModifier($this);
}
return $this->objectBuilderModifier;
}
public function getQueryBuilderModifier()
{
if (is_null($this->queryBuilderModifier)) {
$this->queryBuilderModifier = new SortableBehaviorQueryBuilderModifier($this);
}
return $this->queryBuilderModifier;
}
public function getPeerBuilderModifier()
{
if (is_null($this->peerBuilderModifier)) {
$this->peerBuilderModifier = new SortableBehaviorPeerBuilderModifier($this);
}
return $this->peerBuilderModifier;
}
public function useScope()
{
return $this->getParameter('use_scope') == 'true';
}
}

View file

@ -0,0 +1,636 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Behavior to add sortable columns and abilities
*
* @author François Zaninotto
* @author heltem <heltem@o2php.com>
* @package propel.generator.behavior.sortable
*/
class SortableBehaviorObjectBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
public function __construct($behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
}
protected function getParameter($key)
{
return $this->behavior->getParameter($key);
}
protected function getColumnAttribute($name)
{
return strtolower($this->behavior->getColumnForParameter($name)->getName());
}
protected function getColumnPhpName($name)
{
return $this->behavior->getColumnForParameter($name)->getPhpName();
}
protected function setBuilder($builder)
{
$this->builder = $builder;
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
$this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
}
/**
* Get the getter of the column of the behavior
*
* @return string The related getter, e.g. 'getRank'
*/
protected function getColumnGetter($columnName = 'rank_column')
{
return 'get' . $this->behavior->getColumnForParameter($columnName)->getPhpName();
}
/**
* Get the setter of the column of the behavior
*
* @return string The related setter, e.g. 'setRank'
*/
protected function getColumnSetter($columnName = 'rank_column')
{
return 'set' . $this->behavior->getColumnForParameter($columnName)->getPhpName();
}
public function preSave($builder)
{
return "\$this->processSortableQueries(\$con);";
}
public function preInsert($builder)
{
$useScope = $this->behavior->useScope();
$this->setBuilder($builder);
return "if (!\$this->isColumnModified({$this->peerClassname}::RANK_COL)) {
\$this->{$this->getColumnSetter()}({$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con) + 1);
}
";
}
public function preDelete($builder)
{
$useScope = $this->behavior->useScope();
$this->setBuilder($builder);
return "
{$this->peerClassname}::shiftRank(-1, \$this->{$this->getColumnGetter()}() + 1, null, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
{$this->peerClassname}::clearInstancePool();
";
}
public function objectAttributes($builder)
{
return "
/**
* Queries to be executed in the save transaction
* @var array
*/
protected \$sortableQueries = array();
";
}
public function objectMethods($builder)
{
$this->setBuilder($builder);
$script = '';
if ($this->getParameter('rank_column') != 'rank') {
$this->addRankAccessors($script);
}
if ($this->behavior->useScope() &&
$this->getParameter('scope_column') != 'scope_value') {
$this->addScopeAccessors($script);
}
$this->addIsFirst($script);
$this->addIsLast($script);
$this->addGetNext($script);
$this->addGetPrevious($script);
$this->addInsertAtRank($script);
$this->addInsertAtBottom($script);
$this->addInsertAtTop($script);
$this->addMoveToRank($script);
$this->addSwapWith($script);
$this->addMoveUp($script);
$this->addMoveDown($script);
$this->addMoveToTop($script);
$this->addMoveToBottom($script);
$this->addRemoveFromList($script);
$this->addProcessSortableQueries($script);
return $script;
}
/**
* Get the wraps for getter/setter, if the rank column has not the default name
*
* @return string
*/
protected function addRankAccessors(&$script)
{
$script .= "
/**
* Wrap the getter for rank value
*
* @return int
*/
public function getRank()
{
return \$this->{$this->getColumnAttribute('rank_column')};
}
/**
* Wrap the setter for rank value
*
* @param int
* @return {$this->objectClassname}
*/
public function setRank(\$v)
{
return \$this->{$this->getColumnSetter()}(\$v);
}
";
}
/**
* Get the wraps for getter/setter, if the scope column has not the default name
*
* @return string
*/
protected function addScopeAccessors(&$script)
{
$script .= "
/**
* Wrap the getter for scope value
*
* @return int
*/
public function getScopeValue()
{
return \$this->{$this->getColumnAttribute('scope_column')};
}
/**
* Wrap the setter for scope value
*
* @param int
* @return {$this->objectClassname}
*/
public function setScopeValue(\$v)
{
return \$this->{$this->getColumnSetter('scope_column')}(\$v);
}
";
}
protected function addIsFirst(&$script)
{
$script .= "
/**
* Check if the object is first in the list, i.e. if it has 1 for rank
*
* @return boolean
*/
public function isFirst()
{
return \$this->{$this->getColumnGetter()}() == 1;
}
";
}
protected function addIsLast(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Check if the object is last in the list, i.e. if its rank is the highest rank
*
* @param PropelPDO \$con optional connection
*
* @return boolean
*/
public function isLast(PropelPDO \$con = null)
{
return \$this->{$this->getColumnGetter()}() == {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
}
";
}
protected function addGetNext(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Get the next item in the list, i.e. the one for which rank is immediately higher
*
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname}
*/
public function getNext(PropelPDO \$con = null)
{";
if ($this->behavior->getParameter('rank_column') == 'rank' && $useScope) {
$script .= "
return {$this->queryClassname}::create()
->filterByRank(\$this->{$this->getColumnGetter()}() + 1)
->inList(\$this->{$this->getColumnGetter('scope_column')}())
->findOne(\$con);";
} else {
$script .= "
return {$this->queryClassname}::create()->findOneByRank(\$this->{$this->getColumnGetter()}() + 1, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);";
}
$script .= "
}
";
}
protected function addGetPrevious(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Get the previous item in the list, i.e. the one for which rank is immediately lower
*
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname}
*/
public function getPrevious(PropelPDO \$con = null)
{";
if ($this->behavior->getParameter('rank_column') == 'rank' && $useScope) {
$script .= "
return {$this->queryClassname}::create()
->filterByRank(\$this->{$this->getColumnGetter()}() - 1)
->inList(\$this->{$this->getColumnGetter('scope_column')}())
->findOne(\$con);";
} else {
$script .= "
return {$this->queryClassname}::create()->findOneByRank(\$this->{$this->getColumnGetter()}() - 1, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);";
}
$script .= "
}
";
}
protected function addInsertAtRank(&$script)
{
$useScope = $this->behavior->useScope();
$peerClassname = $this->peerClassname;
$script .= "
/**
* Insert at specified rank
* The modifications are not persisted until the object is saved.
*
* @param integer \$rank rank value
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*
* @throws PropelException
*/
public function insertAtRank(\$rank, PropelPDO \$con = null)
{";
if ($useScope) {
$script .= "
if (null === \$this->{$this->getColumnGetter('scope_column')}()) {
throw new PropelException('The scope must be defined before inserting an object in a suite');
}";
}
$script .= "
\$maxRank = {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
if (\$rank < 1 || \$rank > \$maxRank + 1) {
throw new PropelException('Invalid rank ' . \$rank);
}
// move the object in the list, at the given rank
\$this->{$this->getColumnSetter()}(\$rank);
if (\$rank != \$maxRank + 1) {
// Keep the list modification query for the save() transaction
\$this->sortableQueries []= array(
'callable' => array('$peerClassname', 'shiftRank'),
'arguments' => array(1, \$rank, null, " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}()" : '') . ")
);
}
return \$this;
}
";
}
protected function addInsertAtBottom(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Insert in the last rank
* The modifications are not persisted until the object is saved.
*
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*
* @throws PropelException
*/
public function insertAtBottom(PropelPDO \$con = null)
{";
if ($useScope) {
$script .= "
if (null === \$this->{$this->getColumnGetter('scope_column')}()) {
throw new PropelException('The scope must be defined before inserting an object in a suite');
}";
}
$script .= "
\$this->{$this->getColumnSetter()}({$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con) + 1);
return \$this;
}
";
}
protected function addInsertAtTop(&$script)
{
$script .= "
/**
* Insert in the first rank
* The modifications are not persisted until the object is saved.
*
* @return {$this->objectClassname} the current object
*/
public function insertAtTop()
{
return \$this->insertAtRank(1);
}
";
}
protected function addMoveToRank(&$script)
{
$useScope = $this->behavior->useScope();
$peerClassname = $this->peerClassname;
$script .= "
/**
* Move the object to a new rank, and shifts the rank
* Of the objects inbetween the old and new rank accordingly
*
* @param integer \$newRank rank value
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*
* @throws PropelException
*/
public function moveToRank(\$newRank, PropelPDO \$con = null)
{
if (\$this->isNew()) {
throw new PropelException('New objects cannot be moved. Please use insertAtRank() instead');
}
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
}
if (\$newRank < 1 || \$newRank > {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con)) {
throw new PropelException('Invalid rank ' . \$newRank);
}
\$oldRank = \$this->{$this->getColumnGetter()}();
if (\$oldRank == \$newRank) {
return \$this;
}
\$con->beginTransaction();
try {
// shift the objects between the old and the new rank
\$delta = (\$oldRank < \$newRank) ? -1 : 1;
$peerClassname::shiftRank(\$delta, min(\$oldRank, \$newRank), max(\$oldRank, \$newRank), " . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
// move the object to its new rank
\$this->{$this->getColumnSetter()}(\$newRank);
\$this->save(\$con);
\$con->commit();
return \$this;
} catch (Exception \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
protected function addSwapWith(&$script)
{
$script .= "
/**
* Exchange the rank of the object with the one passed as argument, and saves both objects
*
* @param {$this->objectClassname} \$object
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*
* @throws Exception if the database cannot execute the two updates
*/
public function swapWith(\$object, PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
}
\$con->beginTransaction();
try {
\$oldRank = \$this->{$this->getColumnGetter()}();
\$newRank = \$object->{$this->getColumnGetter()}();
\$this->{$this->getColumnSetter()}(\$newRank);
\$this->save(\$con);
\$object->{$this->getColumnSetter()}(\$oldRank);
\$object->save(\$con);
\$con->commit();
return \$this;
} catch (Exception \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
protected function addMoveUp(&$script)
{
$script .= "
/**
* Move the object higher in the list, i.e. exchanges its rank with the one of the previous object
*
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*/
public function moveUp(PropelPDO \$con = null)
{
if (\$this->isFirst()) {
return \$this;
}
if (\$con === null) {
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
}
\$con->beginTransaction();
try {
\$prev = \$this->getPrevious(\$con);
\$this->swapWith(\$prev, \$con);
\$con->commit();
return \$this;
} catch (Exception \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
protected function addMoveDown(&$script)
{
$script .= "
/**
* Move the object higher in the list, i.e. exchanges its rank with the one of the next object
*
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*/
public function moveDown(PropelPDO \$con = null)
{
if (\$this->isLast(\$con)) {
return \$this;
}
if (\$con === null) {
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
}
\$con->beginTransaction();
try {
\$next = \$this->getNext(\$con);
\$this->swapWith(\$next, \$con);
\$con->commit();
return \$this;
} catch (Exception \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
protected function addMoveToTop(&$script)
{
$script .= "
/**
* Move the object to the top of the list
*
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname} the current object
*/
public function moveToTop(PropelPDO \$con = null)
{
if (\$this->isFirst()) {
return \$this;
}
return \$this->moveToRank(1, \$con);
}
";
}
protected function addMoveToBottom(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Move the object to the bottom of the list
*
* @param PropelPDO \$con optional connection
*
* @return integer the old object's rank
*/
public function moveToBottom(PropelPDO \$con = null)
{
if (\$this->isLast(\$con)) {
return false;
}
if (\$con === null) {
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
}
\$con->beginTransaction();
try {
\$bottom = {$this->queryClassname}::create()->getMaxRank(" . ($useScope ? "\$this->{$this->getColumnGetter('scope_column')}(), " : '') . "\$con);
\$res = \$this->moveToRank(\$bottom, \$con);
\$con->commit();
return \$res;
} catch (Exception \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
protected function addRemoveFromList(&$script)
{
$useScope = $this->behavior->useScope();
$peerClassname = $this->peerClassname;
$script .= "
/**
* Removes the current object from the list.
* The modifications are not persisted until the object is saved.
*
* @return {$this->objectClassname} the current object
*/
public function removeFromList()
{
// Keep the list modification query for the save() transaction
\$this->sortableQueries []= array(
'callable' => array('$peerClassname', 'shiftRank'),
'arguments' => array(-1, \$this->{$this->getColumnGetter()}() + 1, null" . ($useScope ? ", \$this->{$this->getColumnGetter('scope_column')}()" : '') . ")
);
// remove the object from the list
\$this->{$this->getColumnSetter('rank_column')}(null);";
if ($useScope) {
$script .= "
\$this->{$this->getColumnSetter('scope_column')}(null);";
}
$script .= "
return \$this;
}
";
}
protected function addProcessSortableQueries(&$script)
{
$script .= "
/**
* Execute queries that were saved to be run inside the save transaction
*/
protected function processSortableQueries(\$con)
{
foreach (\$this->sortableQueries as \$query) {
\$query['arguments'][]= \$con;
call_user_func_array(\$query['callable'], \$query['arguments']);
}
\$this->sortableQueries = array();
}
";
}
}

View file

@ -0,0 +1,367 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Behavior to add sortable peer methods
*
* @author François Zaninotto
* @author heltem <heltem@o2php.com>
* @package propel.generator.behavior.sortable
*/
class SortableBehaviorPeerBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
public function __construct($behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
}
protected function getParameter($key)
{
return $this->behavior->getParameter($key);
}
protected function getColumnAttribute($name)
{
return strtolower($this->behavior->getColumnForParameter($name)->getName());
}
protected function getColumnConstant($name)
{
return strtoupper($this->behavior->getColumnForParameter($name)->getName());
}
protected function getColumnPhpName($name)
{
return $this->behavior->getColumnForParameter($name)->getPhpName();
}
protected function setBuilder($builder)
{
$this->builder = $builder;
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
}
public function staticAttributes($builder)
{
$tableName = $this->table->getName();
$script = "
/**
* rank column
*/
const RANK_COL = '" . $tableName . '.' . $this->getColumnConstant('rank_column') . "';
";
if ($this->behavior->useScope()) {
$script .= "
/**
* Scope column for the set
*/
const SCOPE_COL = '" . $tableName . '.' . $this->getColumnConstant('scope_column') . "';
";
}
return $script;
}
/**
* Static methods
*
* @return string
*/
public function staticMethods($builder)
{
$this->setBuilder($builder);
$script = '';
$this->addGetMaxRank($script);
$this->addRetrieveByRank($script);
$this->addReorder($script);
$this->addDoSelectOrderByRank($script);
if ($this->behavior->useScope()) {
$this->addRetrieveList($script);
$this->addCountList($script);
$this->addDeleteList($script);
}
$this->addShiftRank($script);
return $script;
}
protected function addGetMaxRank(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Get the highest rank
* ";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which suite to consider";
}
$script .= "
* @param PropelPDO optional connection
*
* @return integer highest position
*/
public static function getMaxRank(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
}
// shift the objects with a position lower than the one of object
\$c = new Criteria();
\$c->addSelectColumn('MAX(' . {$this->peerClassname}::RANK_COL . ')');";
if ($useScope) {
$script .= "
\$c->add({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$stmt = {$this->peerClassname}::doSelectStmt(\$c, \$con);
return \$stmt->fetchColumn();
}
";
}
protected function addRetrieveByRank(&$script)
{
$peerClassname = $this->peerClassname;
$useScope = $this->behavior->useScope();
$script .= "
/**
* Get an item from the list based on its rank
*
* @param integer \$rank rank";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which suite to consider";
}
$script .= "
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname}
*/
public static function retrieveByRank(\$rank, " . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
}
\$c = new Criteria;
\$c->add($peerClassname::RANK_COL, \$rank);";
if($useScope) {
$script .= "
\$c->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
return $peerClassname::doSelectOne(\$c, \$con);
}
";
}
protected function addReorder(&$script)
{
$peerClassname = $this->peerClassname;
$columnGetter = 'get' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
$columnSetter = 'set' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
$script .= "
/**
* Reorder a set of sortable objects based on a list of id/position
* Beware that there is no check made on the positions passed
* So incoherent positions will result in an incoherent list
*
* @param array \$order id => rank pairs
* @param PropelPDO \$con optional connection
*
* @return boolean true if the reordering took place, false if a database problem prevented it
*/
public static function reorder(array \$order, PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
}
\$con->beginTransaction();
try {
\$ids = array_keys(\$order);
\$objects = $peerClassname::retrieveByPKs(\$ids);
foreach (\$objects as \$object) {
\$pk = \$object->getPrimaryKey();
if (\$object->$columnGetter() != \$order[\$pk]) {
\$object->$columnSetter(\$order[\$pk]);
\$object->save(\$con);
}
}
\$con->commit();
return true;
} catch (PropelException \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
protected function addDoSelectOrderByRank(&$script)
{
$peerClassname = $this->peerClassname;
$script .= "
/**
* Return an array of sortable objects ordered by position
*
* @param Criteria \$criteria optional criteria object
* @param string \$order sorting order, to be chosen between Criteria::ASC (default) and Criteria::DESC
* @param PropelPDO \$con optional connection
*
* @return array list of sortable objects
*/
public static function doSelectOrderByRank(Criteria \$criteria = null, \$order = Criteria::ASC, PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
}
if (\$criteria === null) {
\$criteria = new Criteria();
} elseif (\$criteria instanceof Criteria) {
\$criteria = clone \$criteria;
}
\$criteria->clearOrderByColumns();
if (\$order == Criteria::ASC) {
\$criteria->addAscendingOrderByColumn($peerClassname::RANK_COL);
} else {
\$criteria->addDescendingOrderByColumn($peerClassname::RANK_COL);
}
return $peerClassname::doSelect(\$criteria, \$con);
}
";
}
protected function addRetrieveList(&$script)
{
$peerClassname = $this->peerClassname;
$script .= "
/**
* Return an array of sortable objects in the given scope ordered by position
*
* @param int \$scope the scope of the list
* @param string \$order sorting order, to be chosen between Criteria::ASC (default) and Criteria::DESC
* @param PropelPDO \$con optional connection
*
* @return array list of sortable objects
*/
public static function retrieveList(\$scope, \$order = Criteria::ASC, PropelPDO \$con = null)
{
\$c = new Criteria();
\$c->add($peerClassname::SCOPE_COL, \$scope);
return $peerClassname::doSelectOrderByRank(\$c, \$order, \$con);
}
";
}
protected function addCountList(&$script)
{
$peerClassname = $this->peerClassname;
$script .= "
/**
* Return the number of sortable objects in the given scope
*
* @param int \$scope the scope of the list
* @param PropelPDO \$con optional connection
*
* @return array list of sortable objects
*/
public static function countList(\$scope, PropelPDO \$con = null)
{
\$c = new Criteria();
\$c->add($peerClassname::SCOPE_COL, \$scope);
return $peerClassname::doCount(\$c, \$con);
}
";
}
protected function addDeleteList(&$script)
{
$peerClassname = $this->peerClassname;
$script .= "
/**
* Deletes the sortable objects in the given scope
*
* @param int \$scope the scope of the list
* @param PropelPDO \$con optional connection
*
* @return int number of deleted objects
*/
public static function deleteList(\$scope, PropelPDO \$con = null)
{
\$c = new Criteria();
\$c->add($peerClassname::SCOPE_COL, \$scope);
return $peerClassname::doDelete(\$c, \$con);
}
";
}
protected function addShiftRank(&$script)
{
$useScope = $this->behavior->useScope();
$peerClassname = $this->peerClassname;
$script .= "
/**
* Adds \$delta to all Rank values that are >= \$first and <= \$last.
* '\$delta' can also be negative.
*
* @param int \$delta Value to be shifted by, can be negative
* @param int \$first First node to be shifted
* @param int \$last Last node to be shifted";
if($useScope) {
$script .= "
* @param int \$scope Scope to use for the shift";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*/
public static function shiftRank(\$delta, \$first, \$last = null, " . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
}
\$whereCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$criterion = \$whereCriteria->getNewCriterion($peerClassname::RANK_COL, \$first, Criteria::GREATER_EQUAL);
if (null !== \$last) {
\$criterion->addAnd(\$whereCriteria->getNewCriterion($peerClassname::RANK_COL, \$last, Criteria::LESS_EQUAL));
}
\$whereCriteria->add(\$criterion);";
if ($useScope) {
$script .= "
\$whereCriteria->add($peerClassname::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$valuesCriteria = new Criteria($peerClassname::DATABASE_NAME);
\$valuesCriteria->add($peerClassname::RANK_COL, array('raw' => $peerClassname::RANK_COL . ' + ?', 'value' => \$delta), Criteria::CUSTOM_EQUAL);
{$this->builder->getPeerBuilder()->getBasePeerClassname()}::doUpdate(\$whereCriteria, \$valuesCriteria, \$con);
$peerClassname::clearInstancePool();
}
";
}
}

View file

@ -0,0 +1,283 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Behavior to add sortable query methods
*
* @author François Zaninotto
* @package propel.generator.behavior.sortable
*/
class SortableBehaviorQueryBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
public function __construct($behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
}
protected function getParameter($key)
{
return $this->behavior->getParameter($key);
}
protected function getColumn($name)
{
return $this->behavior->getColumnForParameter($name);
}
protected function setBuilder($builder)
{
$this->builder = $builder;
$this->objectClassname = $builder->getStubObjectBuilder()->getClassname();
$this->queryClassname = $builder->getStubQueryBuilder()->getClassname();
$this->peerClassname = $builder->getStubPeerBuilder()->getClassname();
}
public function queryMethods($builder)
{
$this->setBuilder($builder);
$script = '';
// select filters
if ($this->behavior->useScope()) {
$this->addInList($script);
}
if ($this->getParameter('rank_column') != 'rank') {
$this->addFilterByRank($script);
$this->addOrderByRank($script);
}
// select termination methods
if ($this->getParameter('rank_column') != 'rank') {
$this->addFindOneByRank($script);
}
$this->addFindList($script);
// utilities
$this->addGetMaxRank($script);
$this->addReorder($script);
return $script;
}
protected function addInList(&$script)
{
$script .= "
/**
* Returns the objects in a certain list, from the list scope
*
* @param int \$scope Scope to determine which objects node to return
*
* @return {$this->queryClassname} The current query, for fuid interface
*/
public function inList(\$scope = null)
{
return \$this->addUsingAlias({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);
}
";
}
protected function addFilterByRank(&$script)
{
$useScope = $this->behavior->useScope();
$peerClassname = $this->peerClassname;
$script .= "
/**
* Filter the query based on a rank in the list
*
* @param integer \$rank rank";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which suite to consider";
}
$script .= "
*
* @return " . $this->queryClassname . " The current query, for fluid interface
*/
public function filterByRank(\$rank" . ($useScope ? ", \$scope = null" : "") . ")
{
return \$this";
if ($useScope) {
$script .= "
->inList(\$scope)";
}
$script .= "
->addUsingAlias($peerClassname::RANK_COL, \$rank, Criteria::EQUAL);
}
";
}
protected function addOrderByRank(&$script)
{
$script .= "
/**
* Order the query based on the rank in the list.
* Using the default \$order, returns the item with the lowest rank first
*
* @param string \$order either Criteria::ASC (default) or Criteria::DESC
*
* @return " . $this->queryClassname . " The current query, for fluid interface
*/
public function orderByRank(\$order = Criteria::ASC)
{
\$order = strtoupper(\$order);
switch (\$order) {
case Criteria::ASC:
return \$this->addAscendingOrderByColumn(\$this->getAliasedColName(" . $this->peerClassname . "::RANK_COL));
break;
case Criteria::DESC:
return \$this->addDescendingOrderByColumn(\$this->getAliasedColName(" . $this->peerClassname . "::RANK_COL));
break;
default:
throw new PropelException('" . $this->queryClassname . "::orderBy() only accepts \"asc\" or \"desc\" as argument');
}
}
";
}
protected function addFindOneByRank(&$script)
{
$useScope = $this->behavior->useScope();
$peerClassname = $this->peerClassname;
$script .= "
/**
* Get an item from the list based on its rank
*
* @param integer \$rank rank";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which suite to consider";
}
$script .= "
* @param PropelPDO \$con optional connection
*
* @return {$this->objectClassname}
*/
public function findOneByRank(\$rank, " . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{
return \$this
->filterByRank(\$rank" . ($useScope ? ", \$scope" : "") . ")
->findOne(\$con);
}
";
}
protected function addFindList(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Returns " . ($useScope ? 'a' : 'the') ." list of objects
*";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which list to return";
}
$script .= "
* @param PropelPDO \$con Connection to use.
*
* @return mixed the list of results, formatted by the current formatter
*/
public function findList(" . ($useScope ? "\$scope = null, " : "") . "\$con = null)
{
return \$this";
if ($useScope) {
$script .= "
->inList(\$scope)";
}
$script .= "
->orderByRank()
->find(\$con);
}
";
}
protected function addGetMaxRank(&$script)
{
$useScope = $this->behavior->useScope();
$script .= "
/**
* Get the highest rank
* ";
if($useScope) {
$script .= "
* @param int \$scope Scope to determine which suite to consider";
}
$script .= "
* @param PropelPDO optional connection
*
* @return integer highest position
*/
public function getMaxRank(" . ($useScope ? "\$scope = null, " : "") . "PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection({$this->peerClassname}::DATABASE_NAME);
}
// shift the objects with a position lower than the one of object
\$this->addSelectColumn('MAX(' . {$this->peerClassname}::RANK_COL . ')');";
if ($useScope) {
$script .= "
\$this->add({$this->peerClassname}::SCOPE_COL, \$scope, Criteria::EQUAL);";
}
$script .= "
\$stmt = \$this->getSelectStatement(\$con);
return \$stmt->fetchColumn();
}
";
}
protected function addReorder(&$script)
{
$peerClassname = $this->peerClassname;
$columnGetter = 'get' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
$columnSetter = 'set' . $this->behavior->getColumnForParameter('rank_column')->getPhpName();
$script .= "
/**
* Reorder a set of sortable objects based on a list of id/position
* Beware that there is no check made on the positions passed
* So incoherent positions will result in an incoherent list
*
* @param array \$order id => rank pairs
* @param PropelPDO \$con optional connection
*
* @return boolean true if the reordering took place, false if a database problem prevented it
*/
public function reorder(array \$order, PropelPDO \$con = null)
{
if (\$con === null) {
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
}
\$con->beginTransaction();
try {
\$ids = array_keys(\$order);
\$objects = \$this->findPks(\$ids, \$con);
foreach (\$objects as \$object) {
\$pk = \$object->getPrimaryKey();
if (\$object->$columnGetter() != \$order[\$pk]) {
\$object->$columnSetter(\$order[\$pk]);
\$object->save(\$con);
}
}
\$con->commit();
return true;
} catch (PropelException \$e) {
\$con->rollback();
throw \$e;
}
}
";
}
}

View file

@ -0,0 +1,607 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* This is the base class for any builder class that is using the data model.
*
* This could be extended by classes that build SQL DDL, PHP classes, configuration
* files, input forms, etc.
*
* The GeneratorConfig needs to be set on this class in order for the builders
* to be able to access the propel generator build properties. You should be
* safe if you always use the GeneratorConfig to get a configured builder class
* anyway.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder
*/
abstract class DataModelBuilder
{
/**
* The current table.
* @var Table
*/
private $table;
/**
* The generator config object holding build properties, etc.
*
* @var GeneratorConfig
*/
private $generatorConfig;
/**
* An array of warning messages that can be retrieved for display (e.g. as part of phing build process).
* @var array string[]
*/
private $warnings = array();
/**
* Peer builder class for current table.
* @var DataModelBuilder
*/
private $peerBuilder;
/**
* Stub Peer builder class for current table.
* @var DataModelBuilder
*/
private $stubPeerBuilder;
/**
* Object builder class for current table.
* @var DataModelBuilder
*/
private $objectBuilder;
/**
* Stub Object builder class for current table.
* @var DataModelBuilder
*/
private $stubObjectBuilder;
/**
* Query builder class for current table.
* @var DataModelBuilder
*/
private $queryBuilder;
/**
* Stub Query builder class for current table.
* @var DataModelBuilder
*/
private $stubQueryBuilder;
/**
* TableMap builder class for current table.
* @var DataModelBuilder
*/
protected $tablemapBuilder;
/**
* Stub Interface builder class for current table.
* @var DataModelBuilder
*/
private $interfaceBuilder;
/**
* Stub child object for current table.
* @var DataModelBuilder
*/
private $multiExtendObjectBuilder;
/**
* Node object builder for current table.
* @var DataModelBuilder
*/
private $nodeBuilder;
/**
* Node peer builder for current table.
* @var DataModelBuilder
*/
private $nodePeerBuilder;
/**
* Stub node object builder for current table.
* @var DataModelBuilder
*/
private $stubNodeBuilder;
/**
* Stub node peer builder for current table.
* @var DataModelBuilder
*/
private $stubNodePeerBuilder;
/**
* NestedSet object builder for current table.
* @var DataModelBuilder
*/
private $nestedSetBuilder;
/**
* NestedSet peer builder for current table.
* @var DataModelBuilder
*/
private $nestedSetPeerBuilder;
/**
* The DDL builder for current table.
* @var DDLBuilder
*/
private $ddlBuilder;
/**
* The Data-SQL builder for current table.
* @var DataSQLBuilder
*/
private $dataSqlBuilder;
/**
* The Pluralizer class to use.
* @var Pluralizer
*/
private $pluralizer;
/**
* Creates new instance of DataModelBuilder subclass.
* @param Table $table The Table which we are using to build [OM, DDL, etc.].
*/
public function __construct(Table $table)
{
$this->table = $table;
}
/**
* Returns new or existing Peer builder class for this table.
* @return PeerBuilder
*/
public function getPeerBuilder()
{
if (!isset($this->peerBuilder)) {
$this->peerBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'peer');
}
return $this->peerBuilder;
}
/**
* Returns new or existing Pluralizer class.
* @return Pluralizer
*/
public function getPluralizer()
{
if (!isset($this->pluralizer)) {
$this->pluralizer = $this->getGeneratorConfig()->getConfiguredPluralizer();
}
return $this->pluralizer;
}
/**
* Returns new or existing stub Peer builder class for this table.
* @return PeerBuilder
*/
public function getStubPeerBuilder()
{
if (!isset($this->stubPeerBuilder)) {
$this->stubPeerBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'peerstub');
}
return $this->stubPeerBuilder;
}
/**
* Returns new or existing Object builder class for this table.
* @return ObjectBuilder
*/
public function getObjectBuilder()
{
if (!isset($this->objectBuilder)) {
$this->objectBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'object');
}
return $this->objectBuilder;
}
/**
* Returns new or existing stub Object builder class for this table.
* @return ObjectBuilder
*/
public function getStubObjectBuilder()
{
if (!isset($this->stubObjectBuilder)) {
$this->stubObjectBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'objectstub');
}
return $this->stubObjectBuilder;
}
/**
* Returns new or existing Query builder class for this table.
* @return ObjectBuilder
*/
public function getQueryBuilder()
{
if (!isset($this->queryBuilder)) {
$this->queryBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'query');
}
return $this->queryBuilder;
}
/**
* Returns new or existing stub Query builder class for this table.
* @return ObjectBuilder
*/
public function getStubQueryBuilder()
{
if (!isset($this->stubQueryBuilder)) {
$this->stubQueryBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'querystub');
}
return $this->stubQueryBuilder;
}
/**
* Returns new or existing Object builder class for this table.
* @return ObjectBuilder
*/
public function getTableMapBuilder()
{
if (!isset($this->tablemapBuilder)) {
$this->tablemapBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'tablemap');
}
return $this->tablemapBuilder;
}
/**
* Returns new or existing stub Interface builder class for this table.
* @return ObjectBuilder
*/
public function getInterfaceBuilder()
{
if (!isset($this->interfaceBuilder)) {
$this->interfaceBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'interface');
}
return $this->interfaceBuilder;
}
/**
* Returns new or existing stub child object builder class for this table.
* @return ObjectBuilder
*/
public function getMultiExtendObjectBuilder()
{
if (!isset($this->multiExtendObjectBuilder)) {
$this->multiExtendObjectBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'objectmultiextend');
}
return $this->multiExtendObjectBuilder;
}
/**
* Returns new or existing node Object builder class for this table.
* @return ObjectBuilder
*/
public function getNodeBuilder()
{
if (!isset($this->nodeBuilder)) {
$this->nodeBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'node');
}
return $this->nodeBuilder;
}
/**
* Returns new or existing node Peer builder class for this table.
* @return PeerBuilder
*/
public function getNodePeerBuilder()
{
if (!isset($this->nodePeerBuilder)) {
$this->nodePeerBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'nodepeer');
}
return $this->nodePeerBuilder;
}
/**
* Returns new or existing stub node Object builder class for this table.
* @return ObjectBuilder
*/
public function getStubNodeBuilder()
{
if (!isset($this->stubNodeBuilder)) {
$this->stubNodeBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'nodestub');
}
return $this->stubNodeBuilder;
}
/**
* Returns new or existing stub node Peer builder class for this table.
* @return PeerBuilder
*/
public function getStubNodePeerBuilder()
{
if (!isset($this->stubNodePeerBuilder)) {
$this->stubNodePeerBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'nodepeerstub');
}
return $this->stubNodePeerBuilder;
}
/**
* Returns new or existing nested set object builder class for this table.
* @return ObjectBuilder
*/
public function getNestedSetBuilder()
{
if (!isset($this->nestedSetBuilder)) {
$this->nestedSetBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'nestedset');
}
return $this->nestedSetBuilder;
}
/**
* Returns new or existing nested set Peer builder class for this table.
* @return PeerBuilder
*/
public function getNestedSetPeerBuilder()
{
if (!isset($this->nestedSetPeerBuilder)) {
$this->nestedSetPeerBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'nestedsetpeer');
}
return $this->nestedSetPeerBuilder;
}
/**
* Returns new or existing ddl builder class for this table.
* @return DDLBuilder
*/
public function getDDLBuilder()
{
if (!isset($this->ddlBuilder)) {
$this->ddlBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'ddl');
}
return $this->ddlBuilder;
}
/**
* Returns new or existing data sql builder class for this table.
* @return DataSQLBuilder
*/
public function getDataSQLBuilder()
{
if (!isset($this->dataSqlBuilder)) {
$this->dataSqlBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'datasql');
}
return $this->dataSqlBuilder;
}
/**
* Convenience method to return a NEW Peer class builder instance.
*
* This is used very frequently from the peer and object builders to get
* a peer builder for a RELATED table.
*
* @param Table $table
* @return PeerBuilder
*/
public function getNewPeerBuilder(Table $table)
{
return $this->getGeneratorConfig()->getConfiguredBuilder($table, 'peer');
}
/**
* Convenience method to return a NEW Peer stub class builder instance.
*
* This is used from the peer and object builders to get
* a peer builder for a RELATED table.
*
* @param Table $table
* @return PeerBuilder
*/
public function getNewStubPeerBuilder(Table $table)
{
return $this->getGeneratorConfig()->getConfiguredBuilder($table, 'peerstub');
}
/**
* Convenience method to return a NEW Object class builder instance.
*
* This is used very frequently from the peer and object builders to get
* an object builder for a RELATED table.
*
* @param Table $table
* @return ObjectBuilder
*/
public function getNewObjectBuilder(Table $table)
{
return $this->getGeneratorConfig()->getConfiguredBuilder($table, 'object');
}
/**
* Convenience method to return a NEW Object stub class builder instance.
*
* This is used from the query builders to get
* an object builder for a RELATED table.
*
* @param Table $table
* @return ObjectBuilder
*/
public function getNewStubObjectBuilder(Table $table)
{
return $this->getGeneratorConfig()->getConfiguredBuilder($table, 'objectstub');
}
/**
* Convenience method to return a NEW query class builder instance.
*
* This is used from the query builders to get
* a query builder for a RELATED table.
*
* @param Table $table
* @return QueryBuilder
*/
public function getNewQueryBuilder(Table $table)
{
return $this->getGeneratorConfig()->getConfiguredBuilder($table, 'query');
}
/**
* Convenience method to return a NEW query stub class builder instance.
*
* This is used from the query builders to get
* a query builder for a RELATED table.
*
* @param Table $table
* @return QueryBuilder
*/
public function getNewStubQueryBuilder(Table $table)
{
return $this->getGeneratorConfig()->getConfiguredBuilder($table, 'querystub');
}
/**
* Returns new Query Inheritance builder class for this table.
* @return ObjectBuilder
*/
public function getNewQueryInheritanceBuilder($child)
{
$queryInheritanceBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'queryinheritance');
$queryInheritanceBuilder->setChild($child);
return $queryInheritanceBuilder;
}
/**
* Returns new stub Query Inheritance builder class for this table.
* @return ObjectBuilder
*/
public function getNewStubQueryInheritanceBuilder($child)
{
$stubQueryInheritanceBuilder = $this->getGeneratorConfig()->getConfiguredBuilder($this->getTable(), 'queryinheritancestub');
$stubQueryInheritanceBuilder->setChild($child);
return $stubQueryInheritanceBuilder;
}
/**
* Gets the GeneratorConfig object.
*
* @return GeneratorConfig
*/
public function getGeneratorConfig()
{
return $this->generatorConfig;
}
/**
* Get a specific [name transformed] build property.
*
* @param string $name
* @return string
*/
public function getBuildProperty($name)
{
if ($this->getGeneratorConfig()) {
return $this->getGeneratorConfig()->getBuildProperty($name);
}
return null; // just to be explicit
}
/**
* Sets the GeneratorConfig object.
*
* @param GeneratorConfig $v
*/
public function setGeneratorConfig(GeneratorConfig $v)
{
$this->generatorConfig = $v;
}
/**
* Sets the table for this builder.
* @param Table $table
*/
public function setTable(Table $table)
{
$this->table = $table;
}
/**
* Returns the current Table object.
* @return Table
*/
public function getTable()
{
return $this->table;
}
/**
* Convenience method to returns the Platform class for this table (database).
* @return Platform
*/
public function getPlatform()
{
if ($this->getTable() && $this->getTable()->getDatabase()) {
return $this->getTable()->getDatabase()->getPlatform();
}
}
/**
* Convenience method to returns the database for current table.
* @return Database
*/
public function getDatabase()
{
if ($this->getTable()) {
return $this->getTable()->getDatabase();
}
}
/**
* Pushes a message onto the stack of warnings.
* @param string $msg The warning message.
*/
protected function warn($msg)
{
$this->warnings[] = $msg;
}
/**
* Gets array of warning messages.
* @return array string[]
*/
public function getWarnings()
{
return $this->warnings;
}
/**
* Wraps call to Platform->quoteIdentifier() with a check to see whether quoting is enabled.
*
* All subclasses should call this quoteIdentifier() method rather than calling the Platform
* method directly. This method is used by both DataSQLBuilder and DDLBuilder, and potentially
* in the OM builders also, which is why it is defined in this class.
*
* @param string $text The text to quote.
* @return string Quoted text.
*/
public function quoteIdentifier($text)
{
if (!$this->getBuildProperty('disableIdentifierQuoting')) {
return $this->getPlatform()->quoteIdentifier($text);
}
return $text;
}
/**
* Returns the name of the current class being built, with a possible prefix.
* @return string
* @see OMBuilder#getClassname()
*/
public function prefixClassname($identifier)
{
return $this->getBuildProperty('classPrefix') . $identifier;
}
}

View file

@ -0,0 +1,120 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Tools to support class & package inclusion and referencing.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1612 $
* @package propel.generator.builder.om
*/
class ClassTools
{
/**
* Gets just classname, given a dot-path to class.
* @param string $qualifiedName
* @return string
*/
public static function classname($qualifiedName)
{
$pos = strrpos($qualifiedName, '.');
if ($pos === false) {
return $qualifiedName; // there is no '.' in the qualifed name
} else {
return substr($qualifiedName, $pos + 1); // start just after '.'
}
}
/**
* Gets the path to be used in include()/require() statement.
*
* Supports multiple function signatures:
*
* (1) getFilePath($dotPathClass);
* (2) getFilePath($dotPathPrefix, $className);
* (3) getFilePath($dotPathPrefix, $className, $extension);
*
* @param string $path dot-path to class or to package prefix.
* @param string $classname class name
* @param string $extension The extension to use on the file.
* @return string The constructed file path.
*/
public static function getFilePath($path, $classname = null, $extension = '.php')
{
$path = strtr(ltrim($path, '.'), '.', '/');
if ($classname !== null) {
if ($path !== "") { $path .= '/'; }
return $path . $classname . $extension;
} else {
return $path . $extension;
}
}
/**
* Gets the basePeer path if specified for table/db.
* If not, will return 'propel.util.BasePeer'
* @return string
*/
public static function getBasePeer(Table $table) {
$class = $table->getBasePeer();
if ($class === null) {
$class = "propel.util.BasePeer";
}
return $class;
}
/**
* Gets the baseClass path if specified for table/db.
* If not, will return 'propel.om.BaseObject'
* @return string
*/
public static function getBaseClass(Table $table) {
$class = $table->getBaseClass();
if ($class === null) {
$class = "propel.om.BaseObject";
}
return $class;
}
/**
* Gets the interface path if specified for table.
* If not, will return 'propel.om.Persistent'.
* @return string
*/
public static function getInterface(Table $table) {
$interface = $table->getInterface();
if ($interface === null && !$table->isReadOnly()) {
$interface = "propel.om.Persistent";
}
return $interface;
}
/**
* Gets a list of PHP reserved words.
*
* @return array string[]
*/
public static function getPhpReservedWords()
{
return array(
'and', 'or', 'xor', 'exception', '__FILE__', '__LINE__',
'array', 'as', 'break', 'case', 'class', 'const', 'continue',
'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty',
'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile',
'eval', 'exit', 'extends', 'for', 'foreach', 'function', 'global',
'if', 'include', 'include_once', 'isset', 'list', 'new', 'print', 'require',
'require_once', 'return', 'static', 'switch', 'unset', 'use', 'var', 'while',
'__FUNCTION__', '__CLASS__', '__METHOD__', 'final', 'php_user_filter', 'interface',
'implements', 'extends', 'public', 'protected', 'private', 'abstract', 'clone', 'try', 'catch',
'throw', 'this', 'namespace'
);
}
}

View file

@ -0,0 +1,139 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/OMBuilder.php';
/**
* Generates the empty PHP5 stub class for object query
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
* @author Francois Zaninotto
* @package propel.generator.builder.om
*/
class ExtensionQueryBuilder extends OMBuilder
{
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getTable()->getPhpName() . 'Query';
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
$requiredClassFilePath = $this->getQueryBuilder()->getClassFilePath();
$script .="
require '".$requiredClassFilePath."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$this->declareClassFromBuilder($this->getQueryBuilder());
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getQueryBuilder()->getClassname();
$script .= "
/**
* Skeleton subclass for performing query and update operations on the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class ".$this->getClassname()." extends $baseClassname {
";
}
/**
* Specifies the methods that are added as part of the stub query class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see QueryBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
$this->applyBehaviorModifier('extensionQueryFilter', $script, "");
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier = null)
{
return parent::hasBehaviorModifier($hookName, 'QueryBuilderModifier');
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string &$script The script will be modified in this method.
*/
public function applyBehaviorModifier($hookName, &$script, $tab = " ")
{
return $this->applyBehaviorModifierBase($hookName, 'QueryBuilderModifier', $script, $tab);
}
/**
* Checks whether any registered behavior content creator on that table exists a contentName
* @param string $contentName The name of the content as called from one of this class methods, e.g. "parentClassname"
*/
public function getBehaviorContent($contentName)
{
return $this->getBehaviorContentBase($contentName, 'QueryBuilderModifier');
}
}

View file

@ -0,0 +1,138 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/OMBuilder.php';
/**
* Generates the empty PHP5 stub query class for use with single table inheritance.
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
*
* @author François Zaninotto
* @package propel.generator.builder.om
*/
class ExtensionQueryInheritanceBuilder extends OMBuilder
{
/**
* The current child "object" we are operating on.
*/
protected $child;
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getChild()->getClassName() . 'Query';
}
/**
* Set the child object that we're operating on currrently.
* @param $child Inheritance
*/
public function setChild(Inheritance $child)
{
$this->child = $child;
}
/**
* Returns the child object we're operating on currently.
* @return Inheritance
* @throws BuildException - if child was not set.
*/
public function getChild()
{
if (!$this->child) {
throw new BuildException("The PHP5MultiExtendObjectBuilder needs to be told which child class to build (via setChild() method) before it can build the stub class.");
}
return $this->child;
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
$requiredClassFilePath = $this->getStubQueryBuilder()->getClassFilePath();
$script .="
require '".$requiredClassFilePath."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseBuilder = $this->getNewQueryInheritanceBuilder($this->getChild());
$this->declareClassFromBuilder($baseBuilder);
$baseClassname = $baseBuilder->getClassname();
$script .= "
/**
* Skeleton subclass for representing a query for one of the subclasses of the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class " .$this->getClassname() . " extends " . $baseClassname . " {
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
} // MultiExtensionQueryBuilder

View file

@ -0,0 +1,526 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/DataModelBuilder.php';
/**
* Baseclass for OM-building classes.
*
* OM-building classes are those that build a PHP (or other) class to service
* a single table. This includes Peer classes, Entity classes, Map classes,
* Node classes, Nested Set classes, etc.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
abstract class OMBuilder extends DataModelBuilder
{
/**
* Declared fully qualified classnames, to build the 'namespace' statements
* according to this table's namespace.
* @var array
*/
protected $declaredClasses = array();
/**
* Builds the PHP source for current class and returns it as a string.
*
* This is the main entry point and defines a basic structure that classes should follow.
* In most cases this method will not need to be overridden by subclasses. This method
* does assume that the output language is PHP code, so it will need to be overridden if
* this is not the case.
*
* @return string The resulting PHP sourcecode.
*/
public function build()
{
$this->validateModel();
$script = '';
if ($this->isAddIncludes()) {
$this->addIncludes($script);
}
$this->addClassOpen($script);
$this->addClassBody($script);
$this->addClassClose($script);
if($useStatements = $this->getUseStatements($ignoredNamespace = $this->getNamespace())) {
$script = $useStatements . $script;
}
if($namespaceStatement = $this->getNamespaceStatement()) {
$script = $namespaceStatement . $script;
}
//if($this->getTable()->getName() == 'book_club_list') die($ignoredNamespace);
return "<" . "?php
" . $script;
}
/**
* Validates the current table to make sure that it won't
* result in generated code that will not parse.
*
* This method may emit warnings for code which may cause problems
* and will throw exceptions for errors that will definitely cause
* problems.
*/
protected function validateModel()
{
// Validation is currently only implemented in the subclasses.
}
/**
* Creates a $obj = new Book(); code snippet. Can be used by frameworks, for instance, to
* extend this behavior, e.g. initialize the object after creating the instance or so.
*
* @return string Some code
*/
public function buildObjectInstanceCreationCode($objName, $clsName)
{
return "$objName = new $clsName();";
}
/**
* Returns the qualified (prefixed) classname that is being built by the current class.
* This method must be implemented by child classes.
* @return string
*/
abstract public function getUnprefixedClassname();
/**
* Returns the prefixed classname that is being built by the current class.
* @return string
* @see DataModelBuilder#prefixClassname()
*/
public function getClassname()
{
return $this->prefixClassname($this->getUnprefixedClassname());
}
/**
* Returns the namespaced classname if there is a namespace, and the raw classname otherwise
* @return string
*/
public function getFullyQualifiedClassname()
{
if ($namespace = $this->getNamespace()) {
return $namespace . '\\' . $this->getClassname();
} else {
return $this->getClassname();
}
}
/**
* Gets the dot-path representation of current class being built.
* @return string
*/
public function getClasspath()
{
if ($this->getPackage()) {
$path = $this->getPackage() . '.' . $this->getClassname();
} else {
$path = $this->getClassname();
}
return $path;
}
/**
* Gets the full path to the file for the current class.
* @return string
*/
public function getClassFilePath()
{
return ClassTools::getFilePath($this->getPackage(), $this->getClassname());
}
/**
* Gets package name for this table.
* This is overridden by child classes that have different packages.
* @return string
*/
public function getPackage()
{
$pkg = ($this->getTable()->getPackage() ? $this->getTable()->getPackage() : $this->getDatabase()->getPackage());
if (!$pkg) {
$pkg = $this->getBuildProperty('targetPackage');
}
return $pkg;
}
/**
* Returns filesystem path for current package.
* @return string
*/
public function getPackagePath()
{
return strtr($this->getPackage(), '.', '/');
}
/**
* Return the user-defined namespace for this table,
* or the database namespace otherwise.
*
* @return string
*/
public function getNamespace()
{
return $this->getTable()->getNamespace();
}
public function declareClassNamespace($class, $namespace = '')
{
if (isset($this->declaredClasses[$namespace])
&& in_array($class, $this->declaredClasses[$namespace])) {
return;
}
$this->declaredClasses[$namespace][] = $class;
}
public function declareClass($fullyQualifiedClassName)
{
$fullyQualifiedClassName = trim($fullyQualifiedClassName, '\\');
if (($pos = strrpos($fullyQualifiedClassName, '\\')) !== false) {
$this->declareClassNamespace(substr($fullyQualifiedClassName, $pos + 1), substr($fullyQualifiedClassName, 0, $pos));
} else {
// root namespace
$this->declareClassNamespace($fullyQualifiedClassName);
}
}
public function declareClassFromBuilder($builder)
{
$this->declareClassNamespace($builder->getClassname(), $builder->getNamespace());
}
public function declareClasses()
{
$args = func_get_args();
foreach ($args as $class) {
$this->declareClass($class);
}
}
public function getDeclaredClasses($namespace = null)
{
if (null !== $namespace && isset($this->declaredClasses[$namespace])) {
return $this->declaredClasses[$namespace];
} else {
return $this->declaredClasses;
}
}
public function getNamespaceStatement()
{
$namespace = $this->getNamespace();
if ($namespace != '') {
return sprintf("namespace %s;
", $namespace);
}
}
public function getUseStatements($ignoredNamespace = null)
{
$declaredClasses = $this->declaredClasses;
unset($declaredClasses[$ignoredNamespace]);
ksort($declaredClasses);
foreach ($declaredClasses as $namespace => $classes) {
sort($classes);
foreach ($classes as $class) {
$script .= sprintf("use %s\\%s;
", $namespace, $class);
}
}
return $script;
}
/**
* Shortcut method to return the [stub] peer classname for current table.
* This is the classname that is used whenever object or peer classes want
* to invoke methods of the peer classes.
* @return string (e.g. 'MyPeer')
* @see StubPeerBuilder::getClassname()
*/
public function getPeerClassname() {
return $this->getStubPeerBuilder()->getClassname();
}
/**
* Shortcut method to return the [stub] query classname for current table.
* This is the classname that is used whenever object or peer classes want
* to invoke methods of the query classes.
* @return string (e.g. 'Myquery')
* @see StubQueryBuilder::getClassname()
*/
public function getQueryClassname() {
return $this->getStubQueryBuilder()->getClassname();
}
/**
* Returns the object classname for current table.
* This is the classname that is used whenever object or peer classes want
* to invoke methods of the object classes.
* @return string (e.g. 'My')
* @see StubPeerBuilder::getClassname()
*/
public function getObjectClassname() {
return $this->getStubObjectBuilder()->getClassname();
}
/**
* Get the column constant name (e.g. PeerName::COLUMN_NAME).
*
* @param Column $col The column we need a name for.
* @param string $classname The Peer classname to use.
*
* @return string If $classname is provided, then will return $classname::COLUMN_NAME; if not, then the peername is looked up for current table to yield $currTablePeer::COLUMN_NAME.
*/
public function getColumnConstant($col, $classname = null)
{
if ($col === null) {
$e = new Exception("No col specified.");
print $e;
throw $e;
}
if ($classname === null) {
return $this->getBuildProperty('classPrefix') . $col->getConstantName();
}
// was it overridden in schema.xml ?
if ($col->getPeerName()) {
$const = strtoupper($col->getPeerName());
} else {
$const = strtoupper($col->getName());
}
return $classname.'::'.$const;
}
/**
* Gets the basePeer path if specified for table/db.
* If not, will return 'propel.util.BasePeer'
* @return string
*/
public function getBasePeer(Table $table) {
$class = $table->getBasePeer();
if ($class === null) {
$class = "propel.util.BasePeer";
}
return $class;
}
/**
* Convenience method to get the foreign Table object for an fkey.
* @deprecated use ForeignKey::getForeignTable() instead
* @return Table
*/
protected function getForeignTable(ForeignKey $fk)
{
return $this->getTable()->getDatabase()->getTable($fk->getForeignTableName());
}
/**
* Convenience method to get the default Join Type for a relation.
* If the key is required, an INNER JOIN will be returned, else a LEFT JOIN will be suggested,
* unless the schema is provided with the DefaultJoin attribute, which overrules the default Join Type
*
* @param ForeignKey $fk
* @return string
*/
protected function getJoinType(ForeignKey $fk)
{
return $fk->getDefaultJoin() ?
"'".$fk->getDefaultJoin()."'" :
($fk->isLocalColumnsRequired() ? 'Criteria::INNER_JOIN' : 'Criteria::LEFT_JOIN');
}
/**
* Gets the PHP method name affix to be used for fkeys for the current table (not referrers to this table).
*
* The difference between this method and the getRefFKPhpNameAffix() method is that in this method the
* classname in the affix is the foreign table classname.
*
* @param ForeignKey $fk The local FK that we need a name for.
* @param boolean $plural Whether the php name should be plural (e.g. initRelatedObjs() vs. addRelatedObj()
* @return string
*/
public function getFKPhpNameAffix(ForeignKey $fk, $plural = false)
{
if ($fk->getPhpName()) {
if ($plural) {
return $this->getPluralizer()->getPluralForm($fk->getPhpName());
} else {
return $fk->getPhpName();
}
} else {
$className = $fk->getForeignTable()->getPhpName();
if ($plural) {
$className = $this->getPluralizer()->getPluralForm($className);
}
return $className . $this->getRelatedBySuffix($fk);
}
}
/**
* Gets the "RelatedBy*" suffix (if needed) that is attached to method and variable names.
*
* The related by suffix is based on the local columns of the foreign key. If there is more than
* one column in a table that points to the same foreign table, then a 'RelatedByLocalColName' suffix
* will be appended.
*
* @return string
*/
protected static function getRelatedBySuffix(ForeignKey $fk)
{
$relCol = '';
foreach ($fk->getLocalForeignMapping() as $localColumnName => $foreignColumnName) {
$localTable = $fk->getTable();
$localColumn = $localTable->getColumn($localColumnName);
if (!$localColumn) {
throw new Exception("Could not fetch column: $columnName in table " . $localTable->getName());
}
if (count($localTable->getForeignKeysReferencingTable($fk->getForeignTableName())) > 1
|| count($fk->getForeignTable()->getForeignKeysReferencingTable($fk->getTableName())) > 0
|| $fk->getForeignTableName() == $fk->getTableName()) {
// self referential foreign key, or several foreign keys to the same table, or cross-reference fkey
$relCol .= $localColumn->getPhpName();
}
}
if ($relCol != '') {
$relCol = 'RelatedBy' . $relCol;
}
return $relCol;
}
/**
* Gets the PHP method name affix to be used for referencing foreign key methods and variable names (e.g. set????(), $coll???).
*
* The difference between this method and the getFKPhpNameAffix() method is that in this method the
* classname in the affix is the classname of the local fkey table.
*
* @param ForeignKey $fk The referrer FK that we need a name for.
* @param boolean $plural Whether the php name should be plural (e.g. initRelatedObjs() vs. addRelatedObj()
* @return string
*/
public function getRefFKPhpNameAffix(ForeignKey $fk, $plural = false)
{
if ($fk->getRefPhpName()) {
if ($plural) {
return $this->getPluralizer()->getPluralForm($fk->getRefPhpName());
} else {
return $fk->getRefPhpName();
}
} else {
$className = $fk->getTable()->getPhpName();
if ($plural) {
$className = $this->getPluralizer()->getPluralForm($className);
}
return $className . $this->getRefRelatedBySuffix($fk);
}
}
protected static function getRefRelatedBySuffix(ForeignKey $fk)
{
$relCol = '';
foreach ($fk->getLocalForeignMapping() as $localColumnName => $foreignColumnName) {
$localTable = $fk->getTable();
$localColumn = $localTable->getColumn($localColumnName);
if (!$localColumn) {
throw new Exception("Could not fetch column: $columnName in table " . $localTable->getName());
}
$foreignKeysToForeignTable = $localTable->getForeignKeysReferencingTable($fk->getForeignTableName());
if ($fk->getForeignTableName() == $fk->getTableName()) {
// self referential foreign key
$relCol .= $fk->getForeignTable()->getColumn($foreignColumnName)->getPhpName();
if (count($foreignKeysToForeignTable) > 1) {
// several self-referential foreign keys
$relCol .= array_search($fk, $foreignKeysToForeignTable);
}
} elseif (count($foreignKeysToForeignTable) > 1 || count($fk->getForeignTable()->getForeignKeysReferencingTable($fk->getTableName())) > 0) {
// several foreign keys to the same table, or symmetrical foreign key in foreign table
$relCol .= $localColumn->getPhpName();
}
}
if ($relCol != '') {
$relCol = 'RelatedBy' . $relCol;
}
return $relCol;
}
/**
* Whether to add the include statements.
* This is based on the build property propel.addIncludes
*/
protected function isAddIncludes()
{
return $this->getBuildProperty('addIncludes');
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string $modifier The name of the modifier object providing the method in the behavior
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier)
{
$modifierGetter = 'get' . $modifier;
foreach ($this->getTable()->getBehaviors() as $behavior) {
if(method_exists($behavior->$modifierGetter(), $hookName)) {
return true;
}
}
return false;
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string $modifier The name of the modifier object providing the method in the behavior
* @param string &$script The script will be modified in this method.
*/
public function applyBehaviorModifierBase($hookName, $modifier, &$script, $tab = " ")
{
$modifierGetter = 'get' . $modifier;
foreach ($this->getTable()->getBehaviors() as $behavior) {
$modifier = $behavior->$modifierGetter();
if(method_exists($modifier, $hookName)) {
if (strpos($hookName, 'Filter') !== false) {
// filter hook: the script string will be modified by the behavior
$modifier->$hookName($script, $this);
} else {
// regular hook: the behavior returns a string to append to the script string
$script .= "\n" . $tab . '// ' . $behavior->getName() . " behavior\n";
$script .= preg_replace('/^/m', $tab, $modifier->$hookName($this));
}
}
}
}
/**
* Checks whether any registered behavior content creator on that table exists a contentName
* @param string $contentName The name of the content as called from one of this class methods, e.g. "parentClassname"
* @param string $modifier The name of the modifier object providing the method in the behavior
*/
public function getBehaviorContentBase($contentName, $modifier)
{
$modifierGetter = 'get' . $modifier;
foreach ($this->getTable()->getBehaviors() as $behavior) {
$modifier = $behavior->$modifierGetter();
if(method_exists($modifier, $contentName)) {
return $modifier->$contentName($this);
}
}
}
}

View file

@ -0,0 +1,186 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/OMBuilder.php';
/**
* Base class for Peer-building classes.
*
* This class is designed so that it can be extended by a PHP4PeerBuilder in addition
* to the "standard" PHP5PeerBuilder and PHP5ComplexOMPeerBuilder. Hence, this class
* should not have any actual template code in it -- simply basic logic & utility
* methods.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
abstract class ObjectBuilder extends OMBuilder
{
/**
* Constructs a new PeerBuilder subclass.
*/
public function __construct(Table $table) {
parent::__construct($table);
}
/**
* This method adds the contents of the generated class to the script.
*
* This method is abstract and should be overridden by the subclasses.
*
* Hint: Override this method in your subclass if you want to reorganize or
* drastically change the contents of the generated peer class.
*
* @param string &$script The script will be modified in this method.
*/
abstract protected function addClassBody(&$script);
/**
* Adds the getter methods for the column values.
* This is here because it is probably generic enough to apply to templates being generated
* in different langauges (e.g. PHP4 and PHP5).
* @param string &$script The script will be modified in this method.
*/
protected function addColumnAccessorMethods(&$script)
{
$table = $this->getTable();
foreach ($table->getColumns() as $col) {
// if they're not using the DateTime class than we will generate "compatibility" accessor method
if ($col->getType() === PropelTypes::DATE || $col->getType() === PropelTypes::TIME || $col->getType() === PropelTypes::TIMESTAMP) {
$this->addTemporalAccessor($script, $col);
} else {
$this->addDefaultAccessor($script, $col);
}
if ($col->isLazyLoad()) {
$this->addLazyLoader($script, $col);
}
}
}
/**
* Adds the mutator (setter) methods for setting column values.
* This is here because it is probably generic enough to apply to templates being generated
* in different langauges (e.g. PHP4 and PHP5).
* @param string &$script The script will be modified in this method.
*/
protected function addColumnMutatorMethods(&$script)
{
foreach ($this->getTable()->getColumns() as $col) {
if ($col->isLobType()) {
$this->addLobMutator($script, $col);
} elseif ($col->getType() === PropelTypes::DATE || $col->getType() === PropelTypes::TIME || $col->getType() === PropelTypes::TIMESTAMP) {
$this->addTemporalMutator($script, $col);
} else {
$this->addDefaultMutator($script, $col);
}
}
}
/**
* Gets the baseClass path if specified for table/db.
* If not, will return 'propel.om.BaseObject'
* @return string
*/
protected function getBaseClass() {
$class = $this->getTable()->getBaseClass();
if ($class === null) {
$class = "propel.om.BaseObject";
}
return $class;
}
/**
* Gets the interface path if specified for current table.
* If not, will return 'propel.om.Persistent'.
* @return string
*/
protected function getInterface() {
$interface = $this->getTable()->getInterface();
if ($interface === null && !$this->getTable()->isReadOnly()) {
$interface = "propel.om.Persistent";
}
return $interface;
}
/**
* Whether to add the generic mutator methods (setByName(), setByPosition(), fromArray()).
* This is based on the build property propel.addGenericMutators, and also whether the
* table is read-only or an alias.
*/
protected function isAddGenericMutators()
{
$table = $this->getTable();
return (!$table->isAlias() && $this->getBuildProperty('addGenericMutators') && !$table->isReadOnly());
}
/**
* Whether to add the generic accessor methods (getByName(), getByPosition(), toArray()).
* This is based on the build property propel.addGenericAccessors, and also whether the
* table is an alias.
*/
protected function isAddGenericAccessors()
{
$table = $this->getTable();
return (!$table->isAlias() && $this->getBuildProperty('addGenericAccessors'));
}
/**
* Whether to add the validate() method.
* This is based on the build property propel.addValidateMethod
*/
protected function isAddValidateMethod()
{
return $this->getBuildProperty('addValidateMethod');
}
protected function hasDefaultValues()
{
foreach ($this->getTable()->getColumns() as $col) {
if($col->getDefaultValue() !== null) return true;
}
return false;
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier = null)
{
return parent::hasBehaviorModifier($hookName, 'ObjectBuilderModifier');
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string &$script The script will be modified in this method.
*/
public function applyBehaviorModifier($hookName, &$script, $tab = " ")
{
return $this->applyBehaviorModifierBase($hookName, 'ObjectBuilderModifier', $script, $tab);
}
/**
* Checks whether any registered behavior content creator on that table exists a contentName
* @param string $contentName The name of the content as called from one of this class methods, e.g. "parentClassname"
*/
public function getBehaviorContent($contentName)
{
return $this->getBehaviorContentBase($contentName, 'ObjectBuilderModifier');
}
}

View file

@ -0,0 +1,111 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/ObjectBuilder.php';
/**
* Generates the empty PHP5 stub node object class for user object model (OM).
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
* This class replaces the ExtensionNode.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5ExtensionNodeBuilder extends ObjectBuilder
{
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getTable()->getPhpName() . 'Node';
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
$script .= "
require '".$this->getNodeBuilder()->getClassFilePath()."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getNodeBuilder()->getClassname();
$script .= "
/**
* Skeleton subclass for representing a node from the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class ".$this->getClassname()." extends $baseClassname {
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
// there is no class body
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
} // PHP5ExtensionObjectBuilder

View file

@ -0,0 +1,112 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/PeerBuilder.php';
/**
* Generates the empty PHP5 stub node peer class for user object model (OM).
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
* This class replaces the ExtensionNodePeer.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5ExtensionNodePeerBuilder extends PeerBuilder
{
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getStubNodeBuilder()->getClassname() . 'Peer';
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
$script .="
require '".$this->getNodePeerBuilder()->getClassFilePath()."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getNodePeerBuilder()->getClassname();
$script .= "
/**
* Skeleton subclass for performing query and update operations on nodes of the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class ".$this->getClassname()." extends $baseClassname {
";
}
/**
* Specifies the methods that are added as part of the stub peer class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
// there is no class body
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
} // PHP5ExtensionPeerBuilder

View file

@ -0,0 +1,133 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/ObjectBuilder.php';
/**
* Generates the empty PHP5 stub object class for user object model (OM).
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
* This class replaces the ExtensionObject.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5ExtensionObjectBuilder extends ObjectBuilder
{
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getTable()->getPhpName();
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
switch($this->getTable()->treeMode()) {
case 'NestedSet':
$requiredClassFilePath = $this->getNestedSetBuilder()->getClassFilePath();
break;
case 'MaterializedPath':
case 'AdjacencyList':
default:
$requiredClassFilePath = $this->getObjectBuilder()->getClassFilePath();
break;
}
$script .="
require '".$requiredClassFilePath."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$this->declareClassFromBuilder($this->getObjectBuilder());
$tableName = $table->getName();
$tableDesc = $table->getDescription();
switch($table->treeMode()) {
case 'NestedSet':
$baseClassname = $this->getNestedSetBuilder()->getClassname();
break;
case 'MaterializedPath':
case "AdjacencyList":
default:
$baseClassname = $this->getObjectBuilder()->getClassname();
break;
}
$script .= "
/**
* Skeleton subclass for representing a row from the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
".($table->isAbstract() ? "abstract " : "")."class ".$this->getClassname()." extends $baseClassname {
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
$this->applyBehaviorModifier('extensionObjectFilter', $script, "");
}
} // PHP5ExtensionObjectBuilder

View file

@ -0,0 +1,136 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/PeerBuilder.php';
/**
* Generates the empty PHP5 stub peer class for user object model (OM).
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
* This class replaces the ExtensionPeer.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5ExtensionPeerBuilder extends PeerBuilder
{
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getStubObjectBuilder()->getUnprefixedClassname() . 'Peer';
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
switch($this->getTable()->treeMode()) {
case 'NestedSet':
$requiredClassFilePath = $this->getNestedSetPeerBuilder()->getClassFilePath();
break;
case 'MaterializedPath':
case 'AdjacencyList':
default:
$requiredClassFilePath = $this->getPeerBuilder()->getClassFilePath();
break;
}
$script .="
require '".$requiredClassFilePath."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$this->declareClassFromBuilder($this->getPeerBuilder());
$tableName = $table->getName();
$tableDesc = $table->getDescription();
switch($table->treeMode()) {
case 'NestedSet':
$baseClassname = $this->getNestedSetPeerBuilder()->getClassname();
break;
case 'MaterializedPath':
case 'AdjacencyList':
default:
$baseClassname = $this->getPeerBuilder()->getClassname();
break;
}
$script .= "
/**
* Skeleton subclass for performing query and update operations on the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class ".$this->getClassname()." extends $baseClassname {
";
}
/**
* Specifies the methods that are added as part of the stub peer class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
// there is no class body
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
$this->applyBehaviorModifier('extensionPeerFilter', $script, "");
}
} // PHP5ExtensionPeerBuilder

View file

@ -0,0 +1,108 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/ObjectBuilder.php';
/**
* Generates the empty PHP5 stub interface for user object model (OM).
*
* This class produces the empty stub interface when the interface="" attribute is used
* in the the schema xml.
*
* This class replaces the Interface.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5InterfaceBuilder extends ObjectBuilder
{
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return ClassTools::classname($this->getInterface());
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getObjectBuilder()->getClassname();
$script .= "
/**
* This is an interface that should be filled with the public api of the $tableName objects.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional method declarations to this interface to meet the
* application requirements. This interface will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
interface ".$this->getClassname()." {
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
// there is no class body
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
} // PHP5ExtensionObjectBuilder

View file

@ -0,0 +1,196 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/ObjectBuilder.php';
/**
* Generates the empty PHP5 stub object class for use with inheritance in the user object model (OM).
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
* This class replaces the MultiExtendObject.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5MultiExtendObjectBuilder extends ObjectBuilder
{
/**
* The current child "object" we are operating on.
*/
private $child;
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getChild()->getClassname();
}
/**
* Override method to return child package, if specified.
* @return string
*/
public function getPackage()
{
return ($this->child->getPackage() ? $this->child->getPackage() : parent::getPackage());
}
/**
* Set the child object that we're operating on currrently.
* @param $child Inheritance
*/
public function setChild(Inheritance $child)
{
$this->child = $child;
}
/**
* Returns the child object we're operating on currently.
* @return Inheritance
* @throws BuildException - if child was not set.
*/
public function getChild()
{
if (!$this->child) {
throw new BuildException("The PHP5MultiExtendObjectBuilder needs to be told which child class to build (via setChild() method) before it can build the stub class.");
}
return $this->child;
}
/**
* Returns classpath to parent class.
* @return string
*/
protected function getParentClasspath()
{
if ($this->getChild()->getAncestor()) {
return $this->getChild()->getAncestor();
} else {
return $this->getObjectBuilder()->getClasspath();
}
}
/**
* Returns classname of parent class.
* @return string
*/
protected function getParentClassname()
{
return ClassTools::classname($this->getParentClasspath());
}
/**
* Gets the file path to the parent class.
* @return string
*/
protected function getParentClassFilePath()
{
return ClassTools::getFilePath($this->getParentClasspath());
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
if ($this->getChild()->getAncestor()) {
$this->declareClassFromBuilder($this->getNewStubObjectBuilder($this->getDatabase()->getTableByPhpName($this->getChild()->getAncestor())));
} else {
$this->declareClassFromBuilder($this->getObjectBuilder());
}
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getObjectBuilder()->getClassname();
$script .= "
/**
* Skeleton subclass for representing a row from one of the subclasses of the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class ".$this->getClassname()." extends ".$this->getParentClassname()." {
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
$this->declareClassFromBuilder($this->getStubPeerBuilder());
$child = $this->getChild();
$col = $child->getColumn();
$cfc = $col->getPhpName();
$const = "CLASSKEY_".strtoupper($child->getKey());
$script .= "
/**
* Constructs a new ".$this->getChild()->getClassname()." class, setting the ".$col->getName()." column to ".$this->getPeerClassname()."::$const.
*/
public function __construct()
{";
$script .= "
parent::__construct();
\$this->set$cfc(".$this->getPeerClassname()."::CLASSKEY_".strtoupper($child->getKey()).");
}
";
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
} // PHP5ExtensionObjectBuilder

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,754 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/PeerBuilder.php';
/**
* Generates a PHP5 tree node Peer class for user object model (OM).
*
* This class produces the base tree node object class (e.g. BaseMyTable) which contains all
* the custom-built accessor and setter methods.
*
* This class replaces the Node.tpl, with the intent of being easier for users
* to customize (through extending & overriding).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5NodePeerBuilder extends PeerBuilder
{
/**
* Gets the package for the [base] object classes.
* @return string
*/
public function getPackage()
{
return parent::getPackage() . ".om";
}
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getBuildProperty('basePrefix') . $this->getStubNodePeerBuilder()->getUnprefixedClassname();
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$script .= "
/**
* Base static class for performing query operations on the tree contained by the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* @package propel.generator.".$this->getPackage()."
*/
abstract class ".$this->getClassname()." {
";
}
/**
* Specifies the methods that are added as part of the basic OM class.
* This can be overridden by subclasses that wish to add more methods.
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
$table = $this->getTable();
// FIXME
// - Probably the build needs to be customized for supporting
// tables that are "aliases". -- definitely a fringe usecase, though.
$this->addConstants($script);
$this->addIsCodeBase($script);
$this->addRetrieveMethods($script);
$this->addCreateNewRootNode($script);
$this->addInsertNewRootNode($script);
$this->addMoveNodeSubTree($script);
$this->addDeleteNodeSubTree($script);
$this->addBuildFamilyCriteria($script);
$this->addBuildTree($script);
$this->addPopulateNodes($script);
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
protected function addConstants(&$script)
{
$table = $this->getTable();
$npath_colname = '';
$npath_phpname = '';
$npath_len = 0;
$npath_sep = '';
foreach ($table->getColumns() as $col) {
if ($col->isNodeKey()) {
$npath_colname = $table->getName() . '.' . strtoupper($col->getName());
$npath_phpname = $col->getPhpName();
$npath_len = $col->getSize();
$npath_sep = $col->getNodeKeySep();
break;
}
}
$script .= "
const NPATH_COLNAME = '$npath_colname';
const NPATH_PHPNAME = '$npath_phpname';
const NPATH_SEP = '$npath_sep';
const NPATH_LEN = $npath_len;
";
}
protected function addIsCodeBase(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$script .= "
/**
* Temp function for CodeBase hacks that will go away.
*/
public static function isCodeBase(\$con = null)
{
if (\$con === null)
\$con = Propel::getConnection($peerClassname::DATABASE_NAME);
return (get_class(\$con) == 'ODBCConnection' &&
get_class(\$con->getAdapter()) == 'CodeBaseAdapter');
}
";
}
protected function addCreateNewRootNode(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Create a new Node at the top of tree. This method will destroy any
* existing root node (along with its children).
*
* Use at your own risk!
*
* @param $objectClassname Object wrapped by new node.
* @param PropelPDO Connection to use.
* @return $nodeObjectClassname
* @throws PropelException
*/
public static function createNewRootNode(\$obj, PropelPDO \$con = null)
{
if (\$con === null)
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
\$con->beginTransaction();
try {
self::deleteNodeSubTree('1', \$con);
\$setNodePath = 'set' . self::NPATH_PHPNAME;
\$obj->\$setNodePath('1');
\$obj->save(\$con);
\$con->commit();
} catch (PropelException \$e) {
\$con->rollBack();
throw \$e;
}
return new $nodeObjectClassname(\$obj);
}
";
}
protected function addInsertNewRootNode(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Inserts a new Node at the top of tree. Any existing root node (along with
* its children) will be made a child of the new root node. This is a
* safer alternative to createNewRootNode().
*
* @param $objectClassname Object wrapped by new node.
* @param PropelPDO Connection to use.
* @return $nodeObjectClassname
* @throws PropelException
*/
public static function insertNewRootNode(\$obj, PropelPDO \$con = null)
{
if (\$con === null)
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
\$con->beginTransaction();
try {
// Move root tree to an invalid node path.
$nodePeerClassname::moveNodeSubTree('1', '0', \$con);
\$setNodePath = 'set' . self::NPATH_PHPNAME;
// Insert the new root node.
\$obj->\$setNodePath('1');
\$obj->save(\$con);
// Move the old root tree as a child of the new root.
$nodePeerClassname::moveNodeSubTree('0', '1' . self::NPATH_SEP . '1', \$con);
\$con->commit();
} catch (PropelException \$e) {
\$con->rollBack();
throw \$e;
}
return new $nodeObjectClassname(\$obj);
}
";
}
/**
* Adds the methods for retrieving nodes.
*/
protected function addRetrieveMethods(&$script)
{
$this->addRetrieveNodes($script);
$this->addRetrieveNodeByPK($script);
$this->addRetrieveNodeByNP($script);
$this->addRetrieveRootNode($script);
}
protected function addRetrieveNodes(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$script .= "
/**
* Retrieves an array of tree nodes based on specified criteria. Optionally
* includes all parent and/or child nodes of the matching nodes.
*
* @param Criteria Criteria to use.
* @param boolean True if ancestors should also be retrieved.
* @param boolean True if descendants should also be retrieved.
* @param PropelPDO Connection to use.
* @return array Array of root nodes.
*/
public static function retrieveNodes(\$criteria, \$ancestors = false, \$descendants = false, PropelPDO \$con = null)
{
\$criteria = $nodePeerClassname::buildFamilyCriteria(\$criteria, \$ancestors, \$descendants);
\$stmt = ".$this->getStubPeerBuilder()->getClassname()."::doSelectStmt(\$criteria, \$con);
return self::populateNodes(\$stmt, \$criteria);
}
";
}
protected function addRetrieveNodeByPK(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Retrieves a tree node based on a primary key. Optionally includes all
* parent and/or child nodes of the matching node.
*
* @param mixed $objectClassname primary key (array for composite keys)
* @param boolean True if ancestors should also be retrieved.
* @param boolean True if descendants should also be retrieved.
* @param PropelPDO Connection to use.
* @return $nodeObjectClassname
*/
public static function retrieveNodeByPK(\$pk, \$ancestors = false, \$descendants = false, PropelPDO \$con = null)
{
throw new PropelException('retrieveNodeByPK() not implemented yet.');
}
";
}
protected function addRetrieveNodeByNP(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Retrieves a tree node based on a node path. Optionally includes all
* parent and/or child nodes of the matching node.
*
* @param string Node path to retrieve.
* @param boolean True if ancestors should also be retrieved.
* @param boolean True if descendants should also be retrieved.
* @param PropelPDO Connection to use.
* @return $objectClassname
*/
public static function retrieveNodeByNP(\$np, \$ancestors = false, \$descendants = false, PropelPDO \$con = null)
{
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
\$criteria->add(self::NPATH_COLNAME, \$np, Criteria::EQUAL);
\$criteria = self::buildFamilyCriteria(\$criteria, \$ancestors, \$descendants);
\$stmt = $peerClassname::doSelectStmt(\$criteria, \$con);
\$nodes = self::populateNodes(\$stmt, \$criteria);
return (count(\$nodes) == 1 ? \$nodes[0] : null);
}
";
}
protected function addRetrieveRootNode(&$script)
{
$script .= "
/**
* Retrieves the root node.
*
* @param string Node path to retrieve.
* @param boolean True if descendants should also be retrieved.
* @param PropelPDO Connection to use.
* @return ".$this->getStubNodeBuilder()->getClassname()."
*/
public static function retrieveRootNode(\$descendants = false, PropelPDO \$con = null)
{
return self::retrieveNodeByNP('1', false, \$descendants, \$con);
}
";
}
protected function addMoveNodeSubTree(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Moves the node subtree at srcpath to the dstpath. This method is intended
* for internal use by the BaseNode object. Note that it does not check for
* preexisting nodes at the dstpath. It also does not update the node path
* of any Node objects that might currently be in memory.
*
* Use at your own risk!
*
* @param string Source node path to move (root of the src subtree).
* @param string Destination node path to move to (root of the dst subtree).
* @param PropelPDO Connection to use.
* @return void
* @throws PropelException
* @todo This is currently broken for simulated 'onCascadeDelete's.
* @todo Need to abstract the SQL better. The CONCAT sql function doesn't
* seem to be standardized (i.e. mssql), so maybe it needs to be moved
* to DBAdapter.
*/
public static function moveNodeSubTree(\$srcPath, \$dstPath, PropelPDO \$con = null)
{
if (substr(\$dstPath, 0, strlen(\$srcPath)) == \$srcPath)
throw new PropelException('Cannot move a node subtree within itself.');
if (\$con === null)
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
/**
* Example:
* UPDATE table
* SET npath = CONCAT('1.3', SUBSTRING(npath, 6, 74))
* WHERE npath = '1.2.2' OR npath LIKE '1.2.2.%'
*/
\$npath = $nodePeerClassname::NPATH_COLNAME;
//the following dot isn`t mean`t a nodeKeySeperator
\$setcol = substr(\$npath, strrpos(\$npath, '.')+1);
\$setcollen = $nodePeerClassname::NPATH_LEN;
\$db = Propel::getDb($peerClassname::DATABASE_NAME);
// <hack>
if ($nodePeerClassname::isCodeBase(\$con))
{
// This is a hack to get CodeBase working. It will eventually be removed.
// It is a workaround for the following CodeBase bug:
// -Prepared statement parameters cannot be embedded in SQL functions (i.e. CONCAT)
\$sql = \"UPDATE \" . $peerClassname::TABLE_NAME . \" \" .
\"SET \$setcol=\" . \$db->concatString(\"'\$dstPath'\", \$db->subString(\$npath, strlen(\$srcPath)+1, \$setcollen)) . \" \" .
\"WHERE \$npath = '\$srcPath' OR \$npath LIKE '\" . \$srcPath . $nodePeerClassname::NPATH_SEP . \"%'\";
\$con->executeUpdate(\$sql);
}
else
{
// </hack>
\$sql = \"UPDATE \" . $peerClassname::TABLE_NAME . \" \" .
\"SET \$setcol=\" . \$db->concatString('?', \$db->subString(\$npath, '?', '?')) . \" \" .
\"WHERE \$npath = ? OR \$npath LIKE ?\";
\$stmt = \$con->prepare(\$sql);
\$stmt->bindValue(1, \$dstPath); // string
\$srcPathPlus1 = strlen(\$srcPath)+1;
\$stmt->bindValue(2, \$srcPathPlus1); // int
\$stmt->bindValue(3, \$setcollen);// int
\$stmt->bindValue(4, \$srcPath);// string
\$srcPathWC = \$srcPath . $nodePeerClassname::NPATH_SEP . '%';
\$stmt->bindValue(5, \$srcPathWC); // string
\$stmt->execute();
// <hack>
}
}
";
}
protected function addDeleteNodeSubTree(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Deletes the node subtree at the specified node path from the database.
*
* @param string Node path to delete
* @param PropelPDO Connection to use.
* @return void
* @throws PropelException
* @todo This is currently broken for simulated 'onCascadeDelete's.
*/
public static function deleteNodeSubTree(\$nodePath, PropelPDO \$con = null)
{
if (\$con === null)
\$con = Propel::getConnection($peerClassname::DATABASE_NAME, Propel::CONNECTION_WRITE);
/**
* DELETE FROM table
* WHERE npath = '1.2.2' OR npath LIKE '1.2.2.%'
*/
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
\$criteria->add($nodePeerClassname::NPATH_COLNAME, \$nodePath, Criteria::EQUAL);
\$criteria->addOr($nodePeerClassname::NPATH_COLNAME, \$nodePath . self::NPATH_SEP . '%', Criteria::LIKE);
{$this->basePeerClassname}::doDelete(\$criteria, \$con);
}
";
}
protected function addBuildFamilyCriteria(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Builds the criteria needed to retrieve node ancestors and/or descendants.
*
* @param Criteria Criteria to start with
* @param boolean True if ancestors should be retrieved.
* @param boolean True if descendants should be retrieved.
* @return Criteria
*/
public static function buildFamilyCriteria(\$criteria, \$ancestors = false, \$descendants = false)
{
/*
Example SQL to retrieve nodepath '1.2.3' with both ancestors and descendants:
SELECT L.NPATH, L.LABEL, test.NPATH, UCASE(L.NPATH)
FROM test L, test
WHERE test.NPATH='1.2.3' AND
(L.NPATH=SUBSTRING(test.NPATH, 1, LENGTH(L.NPATH)) OR
test.NPATH=SUBSTRING(L.NPATH, 1, LENGTH(test.NPATH)))
ORDER BY UCASE(L.NPATH) ASC
*/
if (\$criteria === null)
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
if (!\$criteria->getSelectColumns())
$peerClassname::addSelectColumns(\$criteria);
\$db = Propel::getDb(\$criteria->getDbName());
if ((\$ancestors || \$descendants) && \$criteria->size())
{
// If we are retrieving ancestors/descendants, we need to do a
// self-join to locate them. The exception to this is if no search
// criteria is specified. In this case we're retrieving all nodes
// anyway, so there is no need to do a self-join.
// The left-side of the self-join will contain the columns we'll
// use to build node objects (target node records along with their
// ancestors and/or descendants). The right-side of the join will
// contain the target node records specified by the initial criteria.
// These are used to match the appropriate ancestor/descendant on
// the left.
// Specify an alias for the left-side table to use.
\$criteria->addAlias('L', $peerClassname::TABLE_NAME);
// Make sure we have select columns to begin with.
if (!\$criteria->getSelectColumns())
$peerClassname::addSelectColumns(\$criteria);
// Replace any existing columns for the right-side table with the
// left-side alias.
\$selectColumns = \$criteria->getSelectColumns();
\$criteria->clearSelectColumns();
foreach (\$selectColumns as \$colName)
\$criteria->addSelectColumn(str_replace($peerClassname::TABLE_NAME, 'L', \$colName));
\$a = null;
\$d = null;
\$npathL = $peerClassname::alias('L', $nodePeerClassname::NPATH_COLNAME);
\$npathR = $nodePeerClassname::NPATH_COLNAME;
\$npath_len = $nodePeerClassname::NPATH_LEN;
if (\$ancestors)
{
// For ancestors, match left-side node paths which are contained
// by right-side node paths.
\$a = \$criteria->getNewCriterion(\$npathL,
\"\$npathL=\" . \$db->subString(\$npathR, 1, \$db->strLength(\$npathL), \$npath_len),
Criteria::CUSTOM);
}
if (\$descendants)
{
// For descendants, match left-side node paths which contain
// right-side node paths.
\$d = \$criteria->getNewCriterion(\$npathR,
\"\$npathR=\" . \$db->subString(\$npathL, 1, \$db->strLength(\$npathR), \$npath_len),
Criteria::CUSTOM);
}
if (\$a)
{
if (\$d) \$a->addOr(\$d);
\$criteria->addAnd(\$a);
}
else if (\$d)
{
\$criteria->addAnd(\$d);
}
// Add the target node path column. This is used by populateNodes().
\$criteria->addSelectColumn(\$npathR);
// Sort by node path to speed up tree construction in populateNodes()
\$criteria->addAsColumn('npathlen', \$db->strLength(\$npathL));
\$criteria->addAscendingOrderByColumn('npathlen');
\$criteria->addAscendingOrderByColumn(\$npathL);
}
else
{
// Add the target node path column. This is used by populateNodes().
\$criteria->addSelectColumn($nodePeerClassname::NPATH_COLNAME);
// Sort by node path to speed up tree construction in populateNodes()
\$criteria->addAsColumn('npathlen', \$db->strLength($nodePeerClassname::NPATH_COLNAME));
\$criteria->addAscendingOrderByColumn('npathlen');
\$criteria->addAscendingOrderByColumn($nodePeerClassname::NPATH_COLNAME);
}
return \$criteria;
}
";
}
protected function addBuildTree(&$script)
{
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* This method reconstructs as much of the tree structure as possible from
* the given array of objects. Depending on how you execute your query, it
* is possible for the ResultSet to contain multiple tree fragments (i.e.
* subtrees). The array returned by this method will contain one entry
* for each subtree root node it finds. The remaining subtree nodes are
* accessible from the $nodeObjectClassname methods of the
* subtree root nodes.
*
* @param array Array of $nodeObjectClassname objects
* @return array Array of $nodeObjectClassname objects
*/
public static function buildTree(\$nodes)
{
// Subtree root nodes to return
\$rootNodes = array();
// Build the tree relations
foreach (\$nodes as \$node)
{
\$sep = strrpos(\$node->getNodePath(), $nodePeerClassname::NPATH_SEP);
\$parentPath = (\$sep !== false ? substr(\$node->getNodePath(), 0, \$sep) : '');
\$parentNode = null;
// Scan other nodes for parent.
foreach (\$nodes as \$pnode)
{
if (\$pnode->getNodePath() === \$parentPath)
{
\$parentNode = \$pnode;
break;
}
}
// If parent was found, attach as child, otherwise its a subtree root
if (\$parentNode)
\$parentNode->attachChildNode(\$node);
else
\$rootNodes[] = \$node;
}
return \$rootNodes;
}
";
}
protected function addPopulateNodes(&$script)
{
$table = $this->getTable();
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$objectClassname = $this->getStubObjectBuilder()->getClassname();
$nodePeerClassname = $this->getStubNodePeerBuilder()->getClassname();
$nodeObjectClassname = $this->getStubNodeBuilder()->getClassname();
$script .= "
/**
* Populates the $objectClassname objects from the
* specified ResultSet, wraps them in $nodeObjectClassname
* objects and build the appropriate node relationships.
* The array returned by this method will only include the initial targets
* of the query, even if ancestors/descendants were also requested.
* The ancestors/descendants will be cached in memory and are accessible via
* the getNode() methods.
*
* @param PDOStatement \$stmt Executed PDOStatement
* @param Criteria
* @return array Array of $nodeObjectClassname objects.
*/
public static function populateNodes(PDOStatement \$stmt, \$criteria)
{
\$nodes = array();
\$targets = array();
\$targetfld = count(\$criteria->getSelectColumns());
";
if (!$table->getChildrenColumn()) {
$script .= "
// set the class once to avoid overhead in the loop
\$cls = $peerClassname::getOMClass();
\$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
";
}
$script .= "
// populate the object(s)
foreach(\$stmt->fetchAll() AS \$row)
{
if (!isset(\$nodes[\$row[0]]))
{
";
if ($table->getChildrenColumn()) {
$script .= "
// class must be set each time from the record row
\$cls = $peerClassname::getOMClass(\$row, 1);
\$cls = substr('.'.\$cls, strrpos('.'.\$cls, '.') + 1);
";
}
$script .= "
" . $this->buildObjectInstanceCreationCode('$obj', '$cls') . "
\$obj->hydrate(\$row);
\$nodes[\$row[0]] = new $nodeObjectClassname(\$obj);
}
\$node = \$nodes[\$row[0]];
if (\$node->getNodePath() === \$row[\$targetfld])
\$targets[\$node->getNodePath()] = \$node;
}
$nodePeerClassname::buildTree(\$nodes);
return array_values(\$targets);
}
";
}
} // PHP5NodePeerBuilder

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,962 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/PHP5ObjectBuilder.php';
/**
* Generates a PHP5 base Object class for user object model (OM).
*
* This class produces the base object class (e.g. BaseMyTable) which contains all
* the custom-built accessor and setter methods.
*
* This class overrides PHP5BaseObject to use Peer methods and Criteria
* instead of Query objects for fetching foreign keys. This can be useful if
* some legacy Propel 1.4 code assumes that the getters returns arrays
* instead of collections.
*
* This class is not used by default. You must override
* the propel.builder.object.class setting in build.properties to use it:
* <code>
* propel.builder.object.class = builder.om.PHP5ObjectNoCollectionBuilder
* </code>
*
* @deprecated Since Propel 1.5
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5ObjectNoCollectionBuilder extends PHP5ObjectBuilder
{
/**
* Adds the lazy loader method.
* @param string &$script The script will be modified in this method.
* @param Column $col The current column.
* @see parent::addColumnAccessors()
*/
protected function addLazyLoader(&$script, Column $col)
{
$this->addLazyLoaderComment($script, $col);
$this->addLazyLoaderOpen($script, $col);
$this->addLazyLoaderBody($script, $col);
$this->addLazyLoaderClose($script, $col);
}
/**
* Adds the comment for the lazy loader method
* @param string &$script The script will be modified in this method.
* @param Column $col The current column.
* @see addLazyLoader()
**/
protected function addLazyLoaderComment(&$script, Column $col) {
$clo = strtolower($col->getName());
$script .= "
/**
* Load the value for the lazy-loaded [$clo] column.
*
* This method performs an additional query to return the value for
* the [$clo] column, since it is not populated by
* the hydrate() method.
*
* @param \$con PropelPDO (optional) The PropelPDO connection to use.
* @return void
* @throws PropelException - any underlying error will be wrapped and re-thrown.
*/";
}
/**
* Adds the function declaration for the lazy loader method
* @param string &$script The script will be modified in this method.
* @param Column $col The current column.
* @see addLazyLoader()
**/
protected function addLazyLoaderOpen(&$script, Column $col) {
$cfc = $col->getPhpName();
$script .= "
protected function load$cfc(PropelPDO \$con = null)
{";
}
/**
* Adds the function body for the lazy loader method
* @param string &$script The script will be modified in this method.
* @param Column $col The current column.
* @see addLazyLoader()
**/
protected function addLazyLoaderBody(&$script, Column $col) {
$platform = $this->getPlatform();
$clo = strtolower($col->getName());
$script .= "
\$c = \$this->buildPkeyCriteria();
\$c->addSelectColumn(".$this->getColumnConstant($col).");
try {
\$stmt = ".$this->getPeerClassname()."::doSelectStmt(\$c, \$con);
\$row = \$stmt->fetch(PDO::FETCH_NUM);
\$stmt->closeCursor();";
if ($col->getType() === PropelTypes::CLOB && $this->getPlatform() instanceof OraclePlatform) {
// PDO_OCI returns a stream for CLOB objects, while other PDO adapters return a string...
$script .= "
\$this->$clo = stream_get_contents(\$row[0]);";
} elseif ($col->isLobType() && !$platform->hasStreamBlobImpl()) {
$script .= "
if (\$row[0] !== null) {
\$this->$clo = fopen('php://memory', 'r+');
fwrite(\$this->$clo, \$row[0]);
rewind(\$this->$clo);
} else {
\$this->$clo = null;
}";
} elseif ($col->isPhpPrimitiveType()) {
$script .= "
\$this->$clo = (\$row[0] !== null) ? (".$col->getPhpType().") \$row[0] : null;";
} elseif ($col->isPhpObjectType()) {
$script .= "
\$this->$clo = (\$row[0] !== null) ? new ".$col->getPhpType()."(\$row[0]) : null;";
} else {
$script .= "
\$this->$clo = \$row[0];";
}
$script .= "
\$this->".$clo."_isLoaded = true;
} catch (Exception \$e) {
throw new PropelException(\"Error loading value for [$clo] column on demand.\", \$e);
}";
}
/**
* Adds the function close for the lazy loader
* @param string &$script The script will be modified in this method.
* @param Column $col The current column.
* @see addLazyLoader()
**/
protected function addLazyLoaderClose(&$script, Column $col) {
$script .= "
}";
} // addLazyLoader()
/**
* Adds the buildPkeyCriteria method
* @param string &$script The script will be modified in this method.
**/
protected function addBuildPkeyCriteria(&$script) {
$this->addBuildPkeyCriteriaComment($script);
$this->addBuildPkeyCriteriaOpen($script);
$this->addBuildPkeyCriteriaBody($script);
$this->addBuildPkeyCriteriaClose($script);
}
/**
* Adds the comment for the buildPkeyCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildPkeyCriteria()
**/
protected function addBuildPkeyCriteriaComment(&$script) {
$script .= "
/**
* Builds a Criteria object containing the primary key for this object.
*
* Unlike buildCriteria() this method includes the primary key values regardless
* of whether or not they have been modified.
*
* @return Criteria The Criteria object containing value(s) for primary key(s).
*/";
}
/**
* Adds the function declaration for the buildPkeyCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildPkeyCriteria()
**/
protected function addBuildPkeyCriteriaOpen(&$script) {
$script .= "
public function buildPkeyCriteria()
{";
}
/**
* Adds the function body for the buildPkeyCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildPkeyCriteria()
**/
protected function addBuildPkeyCriteriaBody(&$script) {
$script .= "
\$criteria = new Criteria(".$this->getPeerClassname()."::DATABASE_NAME);";
foreach ($this->getTable()->getColumns() as $col) {
$clo = strtolower($col->getName());
if ($col->isPrimaryKey()) {
$script .= "
\$criteria->add(".$this->getColumnConstant($col).", \$this->$clo);";
}
}
}
/**
* Adds the function close for the buildPkeyCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildPkeyCriteria()
**/
protected function addBuildPkeyCriteriaClose(&$script) {
$script .= "
return \$criteria;
}
";
}
/**
* Adds the buildCriteria method
* @param string &$script The script will be modified in this method.
**/
protected function addBuildCriteria(&$script)
{
$this->addBuildCriteriaComment($script);
$this->addBuildCriteriaOpen($script);
$this->addBuildCriteriaBody($script);
$this->addBuildCriteriaClose($script);
}
/**
* Adds comment for the buildCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildCriteria()
**/
protected function addBuildCriteriaComment(&$script) {
$script .= "
/**
* Build a Criteria object containing the values of all modified columns in this object.
*
* @return Criteria The Criteria object containing all modified values.
*/";
}
/**
* Adds the function declaration of the buildCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildCriteria()
**/
protected function addBuildCriteriaOpen(&$script) {
$script .= "
public function buildCriteria()
{";
}
/**
* Adds the function body of the buildCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildCriteria()
**/
protected function addBuildCriteriaBody(&$script) {
$script .= "
\$criteria = new Criteria(".$this->getPeerClassname()."::DATABASE_NAME);
";
foreach ($this->getTable()->getColumns() as $col) {
$clo = strtolower($col->getName());
$script .= "
if (\$this->isColumnModified(".$this->getColumnConstant($col).")) \$criteria->add(".$this->getColumnConstant($col).", \$this->$clo);";
}
}
/**
* Adds the function close of the buildCriteria method
* @param string &$script The script will be modified in this method.
* @see addBuildCriteria()
**/
protected function addBuildCriteriaClose(&$script) {
$script .= "
return \$criteria;
}
";
}
/**
* Adds the function body for the delete function
* @param string &$script The script will be modified in this method.
* @see addDelete()
**/
protected function addDeleteBody(&$script) {
$script .= "
if (\$this->isDeleted()) {
throw new PropelException(\"This object has already been deleted.\");
}
if (\$con === null) {
\$con = Propel::getConnection(".$this->getPeerClassname()."::DATABASE_NAME, Propel::CONNECTION_WRITE);
}
\$con->beginTransaction();
try {";
if($this->getGeneratorConfig()->getBuildProperty('addHooks')) {
$script .= "
\$ret = \$this->preDelete(\$con);";
// apply behaviors
$this->applyBehaviorModifier('preDelete', $script, " ");
$script .= "
if (\$ret) {
".$this->getPeerClassname()."::doDelete(\$this, \$con);
\$this->postDelete(\$con);";
// apply behaviors
$this->applyBehaviorModifier('postDelete', $script, " ");
$script .= "
\$con->commit();
\$this->setDeleted(true);
} else {
\$con->commit();
}";
} else {
// apply behaviors
$this->applyBehaviorModifier('preDelete', $script, " ");
$script .= "
".$this->getPeerClassname()."::doDelete(\$this, \$con);";
// apply behaviors
$this->applyBehaviorModifier('postDelete', $script, " ");
$script .= "
\$con->commit();
\$this->setDeleted(true);";
}
$script .= "
} catch (PropelException \$e) {
\$con->rollBack();
throw \$e;
}";
}
/**
* Adds a reload() method to re-fetch the data for this object from the database.
* @param string &$script The script will be modified in this method.
*/
protected function addReload(&$script)
{
$table = $this->getTable();
$script .= "
/**
* Reloads this object from datastore based on primary key and (optionally) resets all associated objects.
*
* This will only work if the object has been saved and has a valid primary key set.
*
* @param boolean \$deep (optional) Whether to also de-associated any related objects.
* @param PropelPDO \$con (optional) The PropelPDO connection to use.
* @return void
* @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db
*/
public function reload(\$deep = false, PropelPDO \$con = null)
{
if (\$this->isDeleted()) {
throw new PropelException(\"Cannot reload a deleted object.\");
}
if (\$this->isNew()) {
throw new PropelException(\"Cannot reload an unsaved object.\");
}
if (\$con === null) {
\$con = Propel::getConnection(".$this->getPeerClassname()."::DATABASE_NAME, Propel::CONNECTION_READ);
}
// We don't need to alter the object instance pool; we're just modifying this instance
// already in the pool.
\$stmt = ".$this->getPeerClassname()."::doSelectStmt(\$this->buildPkeyCriteria(), \$con);
\$row = \$stmt->fetch(PDO::FETCH_NUM);
\$stmt->closeCursor();
if (!\$row) {
throw new PropelException('Cannot find matching row in the database to reload object values.');
}
\$this->hydrate(\$row, 0, true); // rehydrate
";
// support for lazy load columns
foreach ($table->getColumns() as $col) {
if ($col->isLazyLoad()) {
$clo = strtolower($col->getName());
$script .= "
// Reset the $clo lazy-load column
\$this->" . $clo . " = null;
\$this->".$clo."_isLoaded = false;
";
}
}
$script .= "
if (\$deep) { // also de-associate any related objects?
";
foreach ($table->getForeignKeys() as $fk) {
$varName = $this->getFKVarName($fk);
$script .= "
\$this->".$varName." = null;";
}
foreach ($table->getReferrers() as $refFK) {
if ($refFK->isLocalPrimaryKey()) {
$script .= "
\$this->".$this->getPKRefFKVarName($refFK)." = null;
";
} else {
$script .= "
\$this->".$this->getRefFKCollVarName($refFK)." = null;
\$this->".$this->getRefFKLastCriteriaVarName($refFK)." = null;
";
}
}
$script .= "
} // if (deep)
}
";
} // addReload()
/**
* Gets variable name for the Criteria which was used to fetch the objects which
* referencing current table by specified foreign key.
* @param ForeignKey $fk
* @return string
*/
protected function getRefFKLastCriteriaVarName(ForeignKey $fk)
{
return 'last' . $this->getRefFKPhpNameAffix($fk, $plural = false) . 'Criteria';
}
/**
* Adds the accessor (getter) method for getting an fkey related object.
* @param string &$script The script will be modified in this method.
*/
protected function addFKAccessor(&$script, ForeignKey $fk)
{
$table = $this->getTable();
$varName = $this->getFKVarName($fk);
$pCollName = $this->getFKPhpNameAffix($fk, $plural = true);
$fkPeerBuilder = $this->getNewPeerBuilder($this->getForeignTable($fk));
$fkObjectBuilder = $this->getNewObjectBuilder($this->getForeignTable($fk))->getStubObjectBuilder();
$className = $fkObjectBuilder->getClassname(); // get the Classname that has maybe a prefix
$and = "";
$comma = "";
$conditional = "";
$argmap = array(); // foreign -> local mapping
$argsize = 0;
foreach ($fk->getLocalColumns() as $columnName) {
$lfmap = $fk->getLocalForeignMapping();
$localColumn = $table->getColumn($columnName);
$foreignColumn = $fk->getForeignTable()->getColumn($lfmap[$columnName]);
$column = $table->getColumn($columnName);
$cptype = $column->getPhpType();
$clo = strtolower($column->getName());
if ($cptype == "integer" || $cptype == "float" || $cptype == "double") {
$conditional .= $and . "\$this->". $clo ." != 0";
} elseif ($cptype == "string") {
$conditional .= $and . "(\$this->" . $clo ." !== \"\" && \$this->".$clo." !== null)";
} else {
$conditional .= $and . "\$this->" . $clo ." !== null";
}
$argmap[] = array('foreign' => $foreignColumn, 'local' => $localColumn);
$and = " && ";
$comma = ", ";
$argsize = $argsize + 1;
}
// If the related column is a primary kay and if it's a simple association,
// The use retrieveByPk() instead of doSelect() to take advantage of instance pooling
$useRetrieveByPk = count($argmap) == 1 && $argmap[0]['foreign']->isPrimaryKey();
$script .= "
/**
* Get the associated $className object
*
* @param PropelPDO Optional Connection object.
* @return $className The associated $className object.
* @throws PropelException
*/
public function get".$this->getFKPhpNameAffix($fk, $plural = false)."(PropelPDO \$con = null)
{";
$script .= "
if (\$this->$varName === null && ($conditional)) {";
if ($useRetrieveByPk) {
$script .= "
\$this->$varName = ".$fkPeerBuilder->getPeerClassname()."::retrieveByPk(\$this->$clo);";
} else {
$script .= "
\$c = new Criteria(".$fkPeerBuilder->getPeerClassname()."::DATABASE_NAME);";
foreach ($argmap as $el) {
$fcol = $el['foreign'];
$lcol = $el['local'];
$clo = strtolower($lcol->getName());
$script .= "
\$c->add(".$fkPeerBuilder->getColumnConstant($fcol).", \$this->".$clo.");";
}
$script .= "
\$this->$varName = ".$fkPeerBuilder->getPeerClassname()."::doSelectOne(\$c, \$con);";
}
if ($fk->isLocalPrimaryKey()) {
$script .= "
// Because this foreign key represents a one-to-one relationship, we will create a bi-directional association.
\$this->{$varName}->set".$this->getRefFKPhpNameAffix($fk, $plural = false)."(\$this);";
} else {
$script .= "
/* The following can be used additionally to
guarantee the related object contains a reference
to this object. This level of coupling may, however, be
undesirable since it could result in an only partially populated collection
in the referenced object.
\$this->{$varName}->add".$this->getRefFKPhpNameAffix($fk, $plural = true)."(\$this);
*/";
}
$script .= "
}
return \$this->$varName;
}
";
} // addFKAccessor
/**
* Adds the method that fetches fkey-related (referencing) objects but also joins in data from another table.
* @param string &$script The script will be modified in this method.
*/
protected function addRefFKGetJoinMethods(&$script, ForeignKey $refFK)
{
$table = $this->getTable();
$tblFK = $refFK->getTable();
$join_behavior = $this->getGeneratorConfig()->getBuildProperty('useLeftJoinsInDoJoinMethods') ? 'Criteria::LEFT_JOIN' : 'Criteria::INNER_JOIN';
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$relCol = $this->getRefFKPhpNameAffix($refFK, $plural=true);
$collName = $this->getRefFKCollVarName($refFK);
$lastCriteriaName = $this->getRefFKLastCriteriaVarName($refFK);
$fkPeerBuilder = $this->getNewPeerBuilder($tblFK);
$lastTable = "";
foreach ($tblFK->getForeignKeys() as $fk2) {
$tblFK2 = $this->getForeignTable($fk2);
$doJoinGet = !$tblFK2->isForReferenceOnly();
// it doesn't make sense to join in rows from the curent table, since we are fetching
// objects related to *this* table (i.e. the joined rows will all be the same row as current object)
if ($this->getTable()->getPhpName() == $tblFK2->getPhpName()) {
$doJoinGet = false;
}
$relCol2 = $this->getFKPhpNameAffix($fk2, $plural = false);
if ( $this->getRelatedBySuffix($refFK) != "" &&
($this->getRelatedBySuffix($refFK) == $this->getRelatedBySuffix($fk2))) {
$doJoinGet = false;
}
if ($doJoinGet) {
$script .= "
/**
* If this collection has already been initialized with
* an identical criteria, it returns the collection.
* Otherwise if this ".$table->getPhpName()." is new, it will return
* an empty collection; or if this ".$table->getPhpName()." has previously
* been saved, it will retrieve related $relCol from storage.
*
* This method is protected by default in order to keep the public
* api reasonable. You can provide public methods for those you
* actually need in ".$table->getPhpName().".
*/
public function get".$relCol."Join".$relCol2."(\$criteria = null, \$con = null, \$join_behavior = $join_behavior)
{";
$script .= "
if (\$criteria === null) {
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
}
elseif (\$criteria instanceof Criteria)
{
\$criteria = clone \$criteria;
}
if (\$this->$collName === null) {
if (\$this->isNew()) {
\$this->$collName = array();
} else {
";
foreach ($refFK->getForeignColumns() as $columnName) {
$column = $table->getColumn($columnName);
$flMap = $refFK->getForeignLocalMapping();
$colFKName = $flMap[$columnName];
$colFK = $tblFK->getColumn($colFKName);
if ($colFK === null) {
throw new EngineException("Column $colFKName not found in " . $tblFK->getName());
}
$clo = strtolower($column->getName());
$script .= "
\$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->$clo);
";
} // end foreach ($fk->getForeignColumns()
$script .= "
\$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelectJoin$relCol2(\$criteria, \$con, \$join_behavior);
}
} else {
// the following code is to determine if a new query is
// called for. If the criteria is the same as the last
// one, just return the collection.
";
foreach ($refFK->getForeignColumns() as $columnName) {
$column = $table->getColumn($columnName);
$flMap = $refFK->getForeignLocalMapping();
$colFKName = $flMap[$columnName];
$colFK = $tblFK->getColumn($colFKName);
$clo = strtolower($column->getName());
$script .= "
\$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->$clo);
";
} /* end foreach ($fk->getForeignColumns() */
$script .= "
if (!isset(\$this->$lastCriteriaName) || !\$this->".$lastCriteriaName."->equals(\$criteria)) {
\$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelectJoin$relCol2(\$criteria, \$con, \$join_behavior);
}
}
\$this->$lastCriteriaName = \$criteria;
return \$this->$collName;
}
";
} /* end if ($doJoinGet) */
} /* end foreach ($tblFK->getForeignKeys() as $fk2) { */
} // function
/**
* Adds the method that initializes the referrer fkey collection.
* @param string &$script The script will be modified in this method.
*/
protected function addRefFKInit(&$script, ForeignKey $refFK) {
$relCol = $this->getRefFKPhpNameAffix($refFK, $plural = true);
$collName = $this->getRefFKCollVarName($refFK);
$script .= "
/**
* Initializes the $collName collection (array).
*
* By default this just sets the $collName collection to an empty array (like clear$collName());
* however, you may wish to override this method in your stub class to provide setting appropriate
* to your application -- for example, setting the initial array to the values stored in database.
*
* @return void
*/
public function init$relCol()
{
\$this->$collName = array();
}
";
} // addRefererInit()
/**
* Adds the method that adds an object into the referrer fkey collection.
* @param string &$script The script will be modified in this method.
*/
protected function addRefFKAdd(&$script, ForeignKey $refFK)
{
$tblFK = $refFK->getTable();
$joinedTableObjectBuilder = $this->getNewObjectBuilder($refFK->getTable());
$className = $joinedTableObjectBuilder->getObjectClassname();
$collName = $this->getRefFKCollVarName($refFK);
$script .= "
/**
* Method called to associate a $className object to this object
* through the $className foreign key attribute.
*
* @param $className \$l $className
* @return void
* @throws PropelException
*/
public function add".$this->getRefFKPhpNameAffix($refFK, $plural = false)."($className \$l)
{
if (\$this->$collName === null) {
\$this->init".$this->getRefFKPhpNameAffix($refFK, $plural = true)."();
}
if (!in_array(\$l, \$this->$collName, true)) { // only add it if the **same** object is not already associated
array_push(\$this->$collName, \$l);
\$l->set".$this->getFKPhpNameAffix($refFK, $plural = false)."(\$this);
}
}
";
} // addRefererAdd
/**
* Adds the method that returns the size of the referrer fkey collection.
* @param string &$script The script will be modified in this method.
*/
protected function addRefFKCount(&$script, ForeignKey $refFK)
{
$table = $this->getTable();
$tblFK = $refFK->getTable();
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$fkPeerBuilder = $this->getNewPeerBuilder($refFK->getTable());
$relCol = $this->getRefFKPhpNameAffix($refFK, $plural = true);
$collName = $this->getRefFKCollVarName($refFK);
$lastCriteriaName = $this->getRefFKLastCriteriaVarName($refFK);
$className = $fkPeerBuilder->getObjectClassname();
$script .= "
/**
* Returns the number of related $className objects.
*
* @param Criteria \$criteria
* @param boolean \$distinct
* @param PropelPDO \$con
* @return int Count of related $className objects.
* @throws PropelException
*/
public function count$relCol(Criteria \$criteria = null, \$distinct = false, PropelPDO \$con = null)
{";
$script .= "
if (\$criteria === null) {
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
} else {
\$criteria = clone \$criteria;
}
if (\$distinct) {
\$criteria->setDistinct();
}
\$count = null;
if (\$this->$collName === null) {
if (\$this->isNew()) {
\$count = 0;
} else {
";
foreach ($refFK->getLocalColumns() as $colFKName) {
// $colFKName is local to the referring table (i.e. foreign to this table)
$lfmap = $refFK->getLocalForeignMapping();
$localColumn = $this->getTable()->getColumn($lfmap[$colFKName]);
$colFK = $refFK->getTable()->getColumn($colFKName);
$clo = strtolower($localColumn->getName());
$script .= "
\$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->$clo);
";
} // end foreach ($fk->getForeignColumns()
$script .= "
\$count = ".$fkPeerBuilder->getPeerClassname()."::doCount(\$criteria, false, \$con);
}
} else {
// criteria has no effect for a new object
if (!\$this->isNew()) {
// the following code is to determine if a new query is
// called for. If the criteria is the same as the last
// one, just return count of the collection.
";
foreach ($refFK->getLocalColumns() as $colFKName) {
// $colFKName is local to the referring table (i.e. foreign to this table)
$lfmap = $refFK->getLocalForeignMapping();
$localColumn = $this->getTable()->getColumn($lfmap[$colFKName]);
$colFK = $refFK->getTable()->getColumn($colFKName);
$clo = strtolower($localColumn->getName());
$script .= "
\$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->$clo);
";
} // foreach ($fk->getForeignColumns()
$script .= "
if (!isset(\$this->$lastCriteriaName) || !\$this->".$lastCriteriaName."->equals(\$criteria)) {
\$count = ".$fkPeerBuilder->getPeerClassname()."::doCount(\$criteria, false, \$con);
} else {
\$count = count(\$this->$collName);
}
} else {
\$count = count(\$this->$collName);
}
}
return \$count;
}
";
} // addRefererCount
/**
* Adds the method that returns the referrer fkey collection.
* @param string &$script The script will be modified in this method.
*/
protected function addRefFKGet(&$script, ForeignKey $refFK)
{
$table = $this->getTable();
$tblFK = $refFK->getTable();
$peerClassname = $this->getStubPeerBuilder()->getClassname();
$fkPeerBuilder = $this->getNewPeerBuilder($refFK->getTable());
$relCol = $this->getRefFKPhpNameAffix($refFK, $plural = true);
$collName = $this->getRefFKCollVarName($refFK);
$lastCriteriaName = $this->getRefFKLastCriteriaVarName($refFK);
$className = $fkPeerBuilder->getObjectClassname();
$script .= "
/**
* Gets an array of $className objects which contain a foreign key that references this object.
*
* If this collection has already been initialized with an identical Criteria, it returns the collection.
* Otherwise if this ".$this->getObjectClassname()." has previously been saved, it will retrieve
* related $relCol from storage. If this ".$this->getObjectClassname()." is new, it will return
* an empty collection or the current collection, the criteria is ignored on a new object.
*
* @param PropelPDO \$con
* @param Criteria \$criteria
* @return array {$className}[]
* @throws PropelException
*/
public function get$relCol(\$criteria = null, PropelPDO \$con = null)
{";
$script .= "
if (\$criteria === null) {
\$criteria = new Criteria($peerClassname::DATABASE_NAME);
}
elseif (\$criteria instanceof Criteria)
{
\$criteria = clone \$criteria;
}
if (\$this->$collName === null) {
if (\$this->isNew()) {
\$this->$collName = array();
} else {
";
foreach ($refFK->getLocalColumns() as $colFKName) {
// $colFKName is local to the referring table (i.e. foreign to this table)
$lfmap = $refFK->getLocalForeignMapping();
$localColumn = $this->getTable()->getColumn($lfmap[$colFKName]);
$colFK = $refFK->getTable()->getColumn($colFKName);
$clo = strtolower($localColumn->getName());
$script .= "
\$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->$clo);
";
} // end foreach ($fk->getForeignColumns()
$script .= "
".$fkPeerBuilder->getPeerClassname()."::addSelectColumns(\$criteria);
\$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelect(\$criteria, \$con);
}
} else {
// criteria has no effect for a new object
if (!\$this->isNew()) {
// the following code is to determine if a new query is
// called for. If the criteria is the same as the last
// one, just return the collection.
";
foreach ($refFK->getLocalColumns() as $colFKName) {
// $colFKName is local to the referring table (i.e. foreign to this table)
$lfmap = $refFK->getLocalForeignMapping();
$localColumn = $this->getTable()->getColumn($lfmap[$colFKName]);
$colFK = $refFK->getTable()->getColumn($colFKName);
$clo = strtolower($localColumn->getName());
$script .= "
\$criteria->add(".$fkPeerBuilder->getColumnConstant($colFK).", \$this->$clo);
";
} // foreach ($fk->getForeignColumns()
$script .= "
".$fkPeerBuilder->getPeerClassname()."::addSelectColumns(\$criteria);
if (!isset(\$this->$lastCriteriaName) || !\$this->".$lastCriteriaName."->equals(\$criteria)) {
\$this->$collName = ".$fkPeerBuilder->getPeerClassname()."::doSelect(\$criteria, \$con);
}
}
}
\$this->$lastCriteriaName = \$criteria;
return \$this->$collName;
}
";
} // addRefererGet()
/**
* Adds the method that gets a one-to-one related referrer fkey.
* This is for one-to-one relationship special case.
* @param string &$script The script will be modified in this method.
*/
protected function addPKRefFKGet(&$script, ForeignKey $refFK)
{
$table = $this->getTable();
$tblFK = $refFK->getTable();
$joinedTableObjectBuilder = $this->getNewObjectBuilder($refFK->getTable());
$joinedTablePeerBuilder = $this->getNewObjectBuilder($refFK->getTable());
$className = $joinedTableObjectBuilder->getObjectClassname();
$varName = $this->getPKRefFKVarName($refFK);
$script .= "
/**
* Gets a single $className object, which is related to this object by a one-to-one relationship.
*
* @param PropelPDO \$con
* @return $className
* @throws PropelException
*/
public function get".$this->getRefFKPhpNameAffix($refFK, $plural = false)."(PropelPDO \$con = null)
{
";
$script .= "
if (\$this->$varName === null && !\$this->isNew()) {";
$lfmap = $refFK->getLocalForeignMapping();
// remember: this object represents the foreign table,
// so we need foreign columns of the reffk to know the local columns
// that we need to set :)
$localcols = $refFK->getForeignColumns();
// we know that at least every column in the primary key of the foreign table
// is represented in this foreign key
$params = array();
foreach ($tblFK->getPrimaryKey() as $col) {
$localColumn = $table->getColumn($lfmap[$col->getName()]);
$clo = strtolower($localColumn->getName());
$params[] = "\$this->$clo";
}
$script .= "
\$this->$varName = ".$joinedTableObjectBuilder->getPeerClassname()."::retrieveByPK(".implode(", ", $params).", \$con);
}
return \$this->$varName;
}
";
} // addPKRefFKGet()
} // PHP5ObjectBuilder

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,354 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/OMBuilder.php';
/**
* Generates the PHP5 table map class for user object model (OM).
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
class PHP5TableMapBuilder extends OMBuilder
{
/**
* Gets the package for the map builder classes.
* @return string
*/
public function getPackage()
{
return parent::getPackage() . '.map';
}
public function getNamespace()
{
if ($namespace = parent::getNamespace()) {
if ($this->getGeneratorConfig() && $omns = $this->getGeneratorConfig()->getBuildProperty('namespaceMap')) {
return $namespace . '\\' . $omns;
} else {
return $namespace;
}
}
}
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getTable()->getPhpName() . 'TableMap';
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$script .= "
/**
* This class defines the structure of the '".$table->getName()."' table.
*
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
*
* This map class is used by Propel to do runtime db structure discovery.
* For example, the createSelectSql() method checks the type of a given column used in an
* ORDER BY clause to know whether it needs to apply SQL to make the ORDER BY case-insensitive
* (i.e. if it's a text column type).
*
* @package propel.generator.".$this->getPackage()."
*/
class ".$this->getClassname()." extends TableMap {
";
}
/**
* Specifies the methods that are added as part of the map builder class.
* This can be overridden by subclasses that wish to add more methods.
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
$this->declareClasses('TableMap', 'RelationMap');
$this->addConstants($script);
$this->addAttributes($script);
$this->addInitialize($script);
$this->addBuildRelations($script);
$this->addGetBehaviors($script);
}
/**
* Adds any constants needed for this TableMap class.
* @param string &$script The script will be modified in this method.
*/
protected function addConstants(&$script)
{
$script .= "
/**
* The (dot-path) name of this class
*/
const CLASS_NAME = '".$this->getClasspath()."';
";
}
/**
* Adds any attributes needed for this TableMap class.
* @param string &$script The script will be modified in this method.
*/
protected function addAttributes(&$script)
{
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
$this->applyBehaviorModifier('tableMapFilter', $script, "");
}
/**
* Adds the addInitialize() method to the table map class.
* @param string &$script The script will be modified in this method.
*/
protected function addInitialize(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$ddlBuilder = $this->getDDLBuilder();
$script .= "
/**
* Initialize the table attributes, columns and validators
* Relations are not initialized by this method since they are lazy loaded
*
* @return void
* @throws PropelException
*/
public function initialize()
{
// attributes
\$this->setName('".$table->getName()."');
\$this->setPhpName('".$table->getPhpName()."');
\$this->setClassname('" . addslashes($this->getStubObjectBuilder()->getFullyQualifiedClassname()) . "');
\$this->setPackage('" . parent::getPackage() . "');";
if ($table->getIdMethod() == "native") {
$script .= "
\$this->setUseIdGenerator(true);";
} else {
$script .= "
\$this->setUseIdGenerator(false);";
}
if ($table->getIdMethodParameters()) {
$params = $table->getIdMethodParameters();
$imp = $params[0];
$script .= "
\$this->setPrimaryKeyMethodInfo('".$imp->getValue()."');";
} elseif ($table->getIdMethod() == IDMethod::NATIVE && ($platform->getNativeIdMethod() == Platform::SEQUENCE || $platform->getNativeIdMethod() == Platform::SERIAL)) {
$script .= "
\$this->setPrimaryKeyMethodInfo('".$ddlBuilder->getSequenceName()."');";
}
if ($this->getTable()->getChildrenColumn()) {
$script .= "
\$this->setSingleTableInheritance(true);";
}
// Add columns to map
$script .= "
// columns";
foreach ($table->getColumns() as $col) {
$cup=strtoupper($col->getName());
$cfc=$col->getPhpName();
if (!$col->getSize()) {
$size = "null";
} else {
$size = $col->getSize();
}
$default = $col->getDefaultValueString();
if ($col->isPrimaryKey()) {
if ($col->isForeignKey()) {
foreach ($col->getForeignKeys() as $fk) {
$script .= "
\$this->addForeignPrimaryKey('$cup', '$cfc', '".$col->getType()."' , '".$fk->getForeignTableName()."', '".strtoupper($fk->getMappedForeignColumn($col->getName()))."', ".($col->isNotNull() ? 'true' : 'false').", ".$size.", $default);";
}
} else {
$script .= "
\$this->addPrimaryKey('$cup', '$cfc', '".$col->getType()."', ".var_export($col->isNotNull(), true).", ".$size.", $default);";
}
} else {
if ($col->isForeignKey()) {
foreach ($col->getForeignKeys() as $fk) {
$script .= "
\$this->addForeignKey('$cup', '$cfc', '".$col->getType()."', '".$fk->getForeignTableName()."', '".strtoupper($fk->getMappedForeignColumn($col->getName()))."', ".($col->isNotNull() ? 'true' : 'false').", ".$size.", $default);";
}
} else {
$script .= "
\$this->addColumn('$cup', '$cfc', '".$col->getType()."', ".var_export($col->isNotNull(), true).", ".$size.", $default);";
}
} // if col-is prim key
} // foreach
// validators
$script .= "
// validators";
foreach ($table->getValidators() as $val) {
$col = $val->getColumn();
$cup = strtoupper($col->getName());
foreach ($val->getRules() as $rule) {
if ($val->getTranslate() !== Validator::TRANSLATE_NONE) {
$script .= "
\$this->addValidator('$cup', '".$rule->getName()."', '".$rule->getClass()."', '".str_replace("'", "\'", $rule->getValue())."', ".$val->getTranslate()."('".str_replace("'", "\'", $rule->getMessage())."'));";
} else {
$script .= "
\$this->addValidator('$cup', '".$rule->getName()."', '".$rule->getClass()."', '".str_replace("'", "\'", $rule->getValue())."', '".str_replace("'", "\'", $rule->getMessage())."');";
} // if ($rule->getTranslation() ...
} // foreach rule
} // foreach validator
$script .= "
} // initialize()
";
}
/**
* Adds the method that build the RelationMap objects
* @param string &$script The script will be modified in this method.
*/
protected function addBuildRelations(&$script)
{
$script .= "
/**
* Build the RelationMap objects for this table relationships
*/
public function buildRelations()
{";
foreach ($this->getTable()->getForeignKeys() as $fkey)
{
$columnMapping = 'array(';
foreach ($fkey->getLocalForeignMapping() as $key => $value)
{
$columnMapping .= "'$key' => '$value', ";
}
$columnMapping .= ')';
$onDelete = $fkey->hasOnDelete() ? "'" . $fkey->getOnDelete() . "'" : 'null';
$onUpdate = $fkey->hasOnUpdate() ? "'" . $fkey->getOnUpdate() . "'" : 'null';
$script .= "
\$this->addRelation('" . $this->getFKPhpNameAffix($fkey) . "', '" . addslashes($this->getNewStubObjectBuilder($fkey->getForeignTable())->getFullyQualifiedClassname()) . "', RelationMap::MANY_TO_ONE, $columnMapping, $onDelete, $onUpdate);";
}
foreach ($this->getTable()->getReferrers() as $fkey)
{
$columnMapping = 'array(';
foreach ($fkey->getForeignLocalMapping() as $key => $value)
{
$columnMapping .= "'$key' => '$value', ";
}
$columnMapping .= ')';
$onDelete = $fkey->hasOnDelete() ? "'" . $fkey->getOnDelete() . "'" : 'null';
$onUpdate = $fkey->hasOnUpdate() ? "'" . $fkey->getOnUpdate() . "'" : 'null';
$script .= "
\$this->addRelation('" . $this->getRefFKPhpNameAffix($fkey) . "', '" . addslashes($this->getNewStubObjectBuilder($fkey->getTable())->getFullyQualifiedClassname()) . "', RelationMap::ONE_TO_" . ($fkey->isLocalPrimaryKey() ? "ONE" : "MANY") .", $columnMapping, $onDelete, $onUpdate);";
}
foreach ($this->getTable()->getCrossFks() as $fkList)
{
list($refFK, $crossFK) = $fkList;
$onDelete = $fkey->hasOnDelete() ? "'" . $fkey->getOnDelete() . "'" : 'null';
$onUpdate = $fkey->hasOnUpdate() ? "'" . $fkey->getOnUpdate() . "'" : 'null';
$script .= "
\$this->addRelation('" . $this->getFKPhpNameAffix($crossFK) . "', '" . addslashes($this->getNewStubObjectBuilder($crossFK->getForeignTable())->getFullyQualifiedClassname()) . "', RelationMap::MANY_TO_MANY, array(), $onDelete, $onUpdate);";
}
$script .= "
} // buildRelations()
";
}
/**
* Adds the behaviors getter
* @param string &$script The script will be modified in this method.
*/
protected function addGetBehaviors(&$script)
{
if ($behaviors = $this->getTable()->getBehaviors())
{
$script .= "
/**
*
* Gets the list of behaviors registered for this table
*
* @return array Associative array (name => parameters) of behaviors
*/
public function getBehaviors()
{
return array(";
foreach ($behaviors as $behavior)
{
$script .= "
'{$behavior->getName()}' => array(";
foreach ($behavior->getParameters() as $key => $value)
{
$script .= "'$key' => '$value', ";
}
$script .= "),";
}
$script .= "
);
} // getBehaviors()
";
}
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier = null)
{
return parent::hasBehaviorModifier($hookName, 'TableMapBuilderModifier');
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string &$script The script will be modified in this method.
*/
public function applyBehaviorModifier($hookName, &$script, $tab = " ")
{
return $this->applyBehaviorModifierBase($hookName, 'TableMapBuilderModifier', $script, $tab);
}
} // PHP5TableMapBuilder

View file

@ -0,0 +1,305 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/OMBuilder.php';
/**
* Base class for Peer-building classes.
*
* This class is designed so that it can be extended by a PHP4PeerBuilder in addition
* to the "standard" PHP5PeerBuilder and PHP5ComplexOMPeerBuilder. Hence, this class
* should not have any actual template code in it -- simply basic logic & utility
* methods.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.om
*/
abstract class PeerBuilder extends OMBuilder
{
protected $basePeerClass;
protected $basePeerClassname;
/**
* Constructs a new PeerBuilder subclass.
*/
public function __construct(Table $table) {
parent::__construct($table);
$this->basePeerClassname = $this->basePeerClass = $this->getBasePeer($table);
$pos = strrpos($this->basePeerClassname, '.');
if ($pos !== false) {
$this->basePeerClassname = substr($this->basePeerClassname, $pos + 1);
}
}
/**
* Adds the addSelectColumns(), doCount(), etc. methods.
* @param string &$script The script will be modified in this method.
*/
protected function addSelectMethods(&$script)
{
$this->addAddSelectColumns($script);
$this->addDoCount($script);
// consider refactoring the doSelect stuff
// into a top-level method
$this->addDoSelectOne($script);
$this->addDoSelect($script);
$this->addDoSelectStmt($script); // <-- there's PDO code in here
$this->addAddInstanceToPool($script);
$this->addRemoveInstanceFromPool($script);
$this->addGetInstanceFromPool($script);
$this->addClearInstancePool($script);
$this->addClearRelatedInstancePool($script);
$this->addGetPrimaryKeyHash($script);
$this->addGetPrimaryKeyFromRow($script);
$this->addPopulateObjects($script); // <-- there's PDO code in here
$this->addPopulateObject($script);
}
/**
* Adds the correct getOMClass() method, depending on whether this table uses inheritance.
* @param string &$script The script will be modified in this method.
*/
protected function addGetOMClassMethod(&$script)
{
$table = $this->getTable();
if ($table->getChildrenColumn()) {
$this->addGetOMClass_Inheritance($script);
} else {
if ($table->isAbstract()) {
$this->addGetOMClass_NoInheritance_Abstract($script);
} else {
$this->addGetOMClass_NoInheritance($script);
}
}
}
/**
* Adds the doInsert(), doUpdate(), doDeleteAll(), doValidate(), etc. methods.
* @param string &$script The script will be modified in this method.
*/
protected function addUpdateMethods(&$script)
{
$this->addDoInsert($script);
$this->addDoUpdate($script);
$this->addDoDeleteAll($script);
$this->addDoDelete($script);
if ($this->isDeleteCascadeEmulationNeeded()) {
$this->addDoOnDeleteCascade($script);
}
if ($this->isDeleteSetNullEmulationNeeded()) {
$this->addDoOnDeleteSetNull($script);
}
$this->addDoValidate($script);
}
/**
* Adds the retrieveByPK() (and possibly retrieveByPKs()) method(s) appropriate for this class.
* @param string &$script The script will be modified in this method.
*/
protected function addRetrieveByPKMethods(&$script)
{
if (count($this->getTable()->getPrimaryKey()) === 1) {
$this->addRetrieveByPK_SinglePK($script);
$this->addRetrieveByPKs_SinglePK($script);
} else {
$this->addRetrieveByPK_MultiPK($script);
}
}
/**
* This method adds the contents of the generated class to the script.
*
* This method contains the high-level logic that determines which methods
* get generated.
*
* Hint: Override this method in your subclass if you want to reorganize or
* drastically change the contents of the generated peer class.
*
* @param string &$script The script will be modified in this method.
*/
protected function addClassBody(&$script)
{
$table = $this->getTable();
if (!$table->isAlias()) {
$this->addConstantsAndAttributes($script);
}
$this->addTranslateFieldName($script);
$this->addGetFieldNames($script);
if (!$table->isAlias()) {
$this->addAlias($script); // alias() utility method (deprecated?)
$this->addSelectMethods($script);
$this->addGetTableMap($script);
}
$this->addBuildTableMap($script);
$this->addGetOMClassMethod($script);
// add the insert, update, delete, validate etc. methods
if (!$table->isAlias() && !$table->isReadOnly()) {
$this->addUpdateMethods($script);
}
if (count($table->getPrimaryKey()) > 0) {
$this->addRetrieveByPKMethods($script);
}
}
/**
* Whether the platform in use requires ON DELETE CASCADE emulation and whether there are references to this table.
* @return boolean
*/
protected function isDeleteCascadeEmulationNeeded()
{
$table = $this->getTable();
if ((!$this->getPlatform()->supportsNativeDeleteTrigger() || $this->getBuildProperty('emulateForeignKeyConstraints')) && count($table->getReferrers()) > 0) {
foreach ($table->getReferrers() as $fk) {
if ($fk->getOnDelete() == ForeignKey::CASCADE) {
return true;
}
}
}
return false;
}
/**
* Whether the platform in use requires ON DELETE SETNULL emulation and whether there are references to this table.
* @return boolean
*/
protected function isDeleteSetNullEmulationNeeded()
{
$table = $this->getTable();
if ((!$this->getPlatform()->supportsNativeDeleteTrigger() || $this->getBuildProperty('emulateForeignKeyConstraints')) && count($table->getReferrers()) > 0) {
foreach ($table->getReferrers() as $fk) {
if ($fk->getOnDelete() == ForeignKey::SETNULL) {
return true;
}
}
}
return false;
}
/**
* Whether to add the generic mutator methods (setByName(), setByPosition(), fromArray()).
* This is based on the build property propel.addGenericMutators, and also whether the
* table is read-only or an alias.
* @return boolean
*/
protected function isAddGenericMutators()
{
$table = $this->getTable();
return (!$table->isAlias() && $this->getBuildProperty('addGenericMutators') && !$table->isReadOnly());
}
/**
* Whether to add the generic accessor methods (getByName(), getByPosition(), toArray()).
* This is based on the build property propel.addGenericAccessors, and also whether the
* table is an alias.
* @return boolean
*/
protected function isAddGenericAccessors()
{
$table = $this->getTable();
return (!$table->isAlias() && $this->getBuildProperty('addGenericAccessors'));
}
/**
* Returns the retrieveByPK method name to use for this table.
* If the table is an alias then the method name looks like "retrieveTablenameByPK"
* otherwise simply "retrieveByPK".
* @return string
*/
public function getRetrieveMethodName()
{
if ($this->getTable()->isAlias()) {
$retrieveMethod = "retrieve" . $this->getTable()->getPhpName() . "ByPK";
} else {
$retrieveMethod = "retrieveByPK";
}
return $retrieveMethod;
}
/**
* COMPATIBILITY: Get the column constant name (e.g. PeerName::COLUMN_NAME).
*
* This method exists simply because it belonged to the 'PeerBuilder' that this
* class is replacing (because of name conflict more than actual functionality overlap).
* When the new builder model is finished this method will be removed.
*
* @param Column $col The column we need a name for.
* @param string $phpName The PHP Name of the peer class. The 'Peer' is appended automatically.
*
* @return string If $phpName is provided, then will return {$phpName}Peer::COLUMN_NAME; if not, just COLUMN_NAME.
* @deprecated
*/
public static function getColumnName(Column $col, $phpName = null) {
// was it overridden in schema.xml ?
if ($col->getPeerName()) {
$const = strtoupper($col->getPeerName());
} else {
$const = strtoupper($col->getName());
}
if ($phpName !== null) {
return $phpName . 'Peer::' . $const;
} else {
return $const;
}
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier = null)
{
return parent::hasBehaviorModifier($hookName, 'PeerBuilderModifier');
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string &$script The script will be modified in this method.
*/
public function applyBehaviorModifier($hookName, &$script, $tab = " ")
{
return $this->applyBehaviorModifierBase($hookName, 'PeerBuilderModifier', $script, $tab);
}
/**
* Checks whether any registered behavior content creator on that table exists a contentName
* @param string $contentName The name of the content as called from one of this class methods, e.g. "parentClassname"
*/
public function getBehaviorContent($contentName)
{
return $this->getBehaviorContentBase($contentName, 'PeerBuilderModifier');
}
/**
* Get the BasePeer class name for the current table (e.g. 'BasePeer')
*
* @return string The Base Peer Class name
*/
public function getBasePeerClassname()
{
return $this->basePeerClassname;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,276 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/om/OMBuilder.php';
/**
* Generates the empty PHP5 stub query class for use with single table inheritance.
*
* This class produces the empty stub class that can be customized with application
* business logic, custom behavior, etc.
*
*
* @author François Zaninotto
* @package propel.generator.builder.om
*/
class QueryInheritanceBuilder extends OMBuilder
{
/**
* The current child "object" we are operating on.
*/
protected $child;
/**
* Returns the name of the current class being built.
* @return string
*/
public function getUnprefixedClassname()
{
return $this->getBuildProperty('basePrefix') . $this->getNewStubQueryInheritanceBuilder($this->getChild())->getUnprefixedClassname();
}
/**
* Gets the package for the [base] object classes.
* @return string
*/
public function getPackage()
{
return parent::getPackage() . ".om";
}
public function getNamespace()
{
if ($namespace = parent::getNamespace()) {
if ($this->getGeneratorConfig() && $omns = $this->getGeneratorConfig()->getBuildProperty('namespaceOm')) {
return $namespace . '\\' . $omns;
} else {
return $namespace;
}
}
}
/**
* Set the child object that we're operating on currrently.
* @param $child Inheritance
*/
public function setChild(Inheritance $child)
{
$this->child = $child;
}
/**
* Returns the child object we're operating on currently.
* @return Inheritance
* @throws BuildException - if child was not set.
*/
public function getChild()
{
if (!$this->child) {
throw new BuildException("The PHP5MultiExtendObjectBuilder needs to be told which child class to build (via setChild() method) before it can build the stub class.");
}
return $this->child;
}
/**
* Adds the include() statements for files that this class depends on or utilizes.
* @param string &$script The script will be modified in this method.
*/
protected function addIncludes(&$script)
{
$requiredClassFilePath = $this->getStubQueryBuilder()->getClassFilePath();
$script .="
require '".$requiredClassFilePath."';
";
} // addIncludes()
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseBuilder = $this->getStubQueryBuilder();
$this->declareClassFromBuilder($baseBuilder);
$baseClassname = $baseBuilder->getClassname();
$script .= "
/**
* Skeleton subclass for representing a query for one of the subclasses of the '$tableName' table.
*
* $tableDesc
*";
if ($this->getBuildProperty('addTimeStamp')) {
$now = strftime('%c');
$script .= "
* This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
*
* $now
*";
}
$script .= "
* You should add additional methods to this class to meet the
* application requirements. This class will only be generated as
* long as it does not already exist in the output directory.
*
* @package propel.generator.".$this->getPackage()."
*/
class " .$this->getClassname() . " extends " . $baseClassname . " {
";
}
/**
* Specifies the methods that are added as part of the stub object class.
*
* By default there are no methods for the empty stub classes; override this method
* if you want to change that behavior.
*
* @see ObjectBuilder::addClassBody()
*/
protected function addClassBody(&$script)
{
$this->declareClassFromBuilder($this->getStubPeerBuilder());
$this->declareClasses('PropelPDO', 'Criteria');
$this->addFactory($script);
$this->addPreSelect($script);
$this->addPreUpdate($script);
$this->addPreDelete($script);
$this->addDoDeleteAll($script);
}
/**
* Adds the factory for this object.
* @param string &$script The script will be modified in this method.
*/
protected function addFactory(&$script)
{
$builder = $this->getNewStubQueryInheritanceBuilder($this->getChild());
$this->declareClassFromBuilder($builder);
$classname = $builder->getClassname();
$script .= "
/**
* Returns a new " . $classname . " object.
*
* @param string \$modelAlias The alias of a model in the query
* @param Criteria \$criteria Optional Criteria to build the query from
*
* @return " . $classname . "
*/
public static function create(\$modelAlias = null, \$criteria = null)
{
if (\$criteria instanceof " . $classname . ") {
return \$criteria;
}
\$query = new " . $classname . "();
if (null !== \$modelAlias) {
\$query->setModelAlias(\$modelAlias);
}
if (\$criteria instanceof Criteria) {
\$query->mergeWith(\$criteria);
}
return \$query;
}
";
}
protected function addPreSelect(&$script)
{
$child = $this->getChild();
$col = $child->getColumn();
$script .= "
/**
* Filters the query to target only " . $child->getClassname() . " objects.
*/
public function preSelect(PropelPDO \$con)
{
" . $this->getClassKeyCondition() . "
}
";
}
protected function addPreUpdate(&$script)
{
$child = $this->getChild();
$col = $child->getColumn();
$script .= "
/**
* Filters the query to target only " . $child->getClassname() . " objects.
*/
public function preUpdate(&\$values, PropelPDO \$con, \$forceIndividualSaves = false)
{
" . $this->getClassKeyCondition() . "
}
";
}
protected function addPreDelete(&$script)
{
$child = $this->getChild();
$col = $child->getColumn();
$script .= "
/**
* Filters the query to target only " . $child->getClassname() . " objects.
*/
public function preDelete(PropelPDO \$con)
{
" . $this->getClassKeyCondition() . "
}
";
}
protected function getClassKeyCondition()
{
$child = $this->getChild();
$col = $child->getColumn();
return "\$this->addUsingAlias(" . $col->getConstantName() . ", " . $this->getPeerClassname()."::CLASSKEY_".strtoupper($child->getKey()).");";
}
protected function addDoDeleteAll(&$script)
{
$child = $this->getChild();
$script .= "
/**
* Issue a DELETE query based on the current ModelCriteria deleting all rows in the table
* Having the " . $child->getClassname() . " class.
* This method is called by ModelCriteria::deleteAll() inside a transaction
*
* @param PropelPDO \$con a connection object
*
* @return integer the number of deleted rows
*/
public function doDeleteAll(\$con)
{
// condition on class key is already added in preDelete()
return parent::doDelete(\$con);
}
";
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
} // " . $this->getClassname() . "
";
}
} // MultiExtensionQueryBuilder

View file

@ -0,0 +1,166 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/DataModelBuilder.php';
/**
* Baseclass for SQL DDL-building classes.
*
* DDL-building classes are those that build all the SQL DDL for a single table.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql
*/
abstract class DDLBuilder extends DataModelBuilder
{
/**
* Builds the SQL for current table and returns it as a string.
*
* This is the main entry point and defines a basic structure that classes should follow.
* In most cases this method will not need to be overridden by subclasses.
*
* @return string The resulting SQL DDL.
*/
public function build()
{
$script = "";
$this->addTable($script);
$this->addIndices($script);
$this->addForeignKeys($script);
return $script;
}
/**
* Gets the name to use for creating a sequence for the current table.
*
* This will create a new name or use one specified in an id-method-parameter
* tag, if specified.
*
* @return string Sequence name for this table.
*/
public function getSequenceName()
{
$table = $this->getTable();
static $longNamesMap = array();
$result = null;
if ($table->getIdMethod() == IDMethod::NATIVE) {
$idMethodParams = $table->getIdMethodParameters();
$maxIdentifierLength = $table->getDatabase()->getPlatform()->getMaxColumnNameLength();
if (empty($idMethodParams)) {
if (strlen($table->getName() . "_SEQ") > $maxIdentifierLength) {
if (!isset($longNamesMap[$table->getName()])) {
$longNamesMap[$table->getName()] = strval(count($longNamesMap) + 1);
}
$result = substr($table->getName(), 0, $maxIdentifierLength - strlen("_SEQ_" . $longNamesMap[$table->getName()])) . "_SEQ_" . $longNamesMap[$table->getName()];
}
else {
$result = substr($table->getName(), 0, $maxIdentifierLength -4) . "_SEQ";
}
} else {
$result = substr($idMethodParams[0]->getValue(), 0, $maxIdentifierLength);
}
}
return $result;
}
/**
* Builds the DDL SQL for a Column object.
* @return string
*/
public function getColumnDDL(Column $col)
{
$platform = $this->getPlatform();
$domain = $col->getDomain();
$sb = "";
$sb .= $this->quoteIdentifier($col->getName()) . " ";
$sb .= $domain->getSqlType();
if ($platform->hasSize($domain->getSqlType())) {
$sb .= $domain->printSize();
}
$sb .= " ";
$sb .= $col->getDefaultSetting() . " ";
$sb .= $col->getNotNullString() . " ";
$sb .= $col->getAutoIncrementString();
return trim($sb);
}
/**
* Creates a delimiter-delimited string list of column names, quoted using quoteIdentifier().
* @param array Column[] or string[]
* @param string $delim The delimiter to use in separating the column names.
* @return string
*/
public function getColumnList($columns, $delim=',')
{
$list = array();
foreach ($columns as $col) {
if ($col instanceof Column) {
$col = $col->getName();
}
$list[] = $this->quoteIdentifier($col);
}
return implode($delim, $list);
}
/**
* This function adds any _database_ start/initialization SQL.
* This is designed to be called for a database, not a specific table, hence it is static.
* @return string The DDL is returned as astring.
*/
public static function getDatabaseStartDDL()
{
return '';
}
/**
* This function adds any _database_ end/cleanup SQL.
* This is designed to be called for a database, not a specific table, hence it is static.
* @return string The DDL is returned as astring.
*/
public static function getDatabaseEndDDL()
{
return '';
}
/**
* Resets any static variables between building a SQL file for a database.
*
* Theoretically, Propel could build multiple .sql files for multiple databases; in
* many cases we don't want static values to persist between these. This method provides
* a way to clear out static values between iterations, if the subclasses choose to implement
* it.
*/
public static function reset()
{
// nothing by default
}
/**
* Adds table definition.
* @param string &$script The script will be modified in this method.
*/
abstract protected function addTable(&$script);
/**
* Adds index definitions.
* @param string &$script The script will be modified in this method.
*/
abstract protected function addIndices(&$script);
/**
* Adds foreign key constraint definitions.
* @param string &$script The script will be modified in this method.
*/
abstract protected function addForeignKeys(&$script);
}

View file

@ -0,0 +1,253 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/DataModelBuilder.php';
require_once 'model/PropelTypes.php';
/**
* Baseclass for SQL data dump SQL building classes.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql
*/
abstract class DataSQLBuilder extends DataModelBuilder
{
/**
* Perform any reset between runs of this builder.
*
* This can be used, for example, to clear any stored start/end SQL.
*/
public static function reset()
{
// does nothing by default
}
/**
* Gets any SQL to place at the start of all the row inserts.
*
* @return string
*/
public static function getDatabaseStartSql()
{
return '';
}
/**
* Gets any SQL to place at the end of all the row inserts.
*
* @return string
*/
public static function getDatabaseEndSql()
{
return '';
}
/**
* Gets any SQL to place before row inserts for a new table.
*
* @return string
*/
public function getTableStartSql()
{
return '';
}
/**
* Gets any SQL to place at the end of row inserts for a table.
*
* @return string
*/
public function getTableEndSql()
{
return '';
}
/**
* The main method in this class, returns the SQL for INSERTing data into a row.
* @param DataRow $row The row to process.
* @return string
*/
public function buildRowSql(DataRow $row)
{
$sql = "";
$platform = $this->getPlatform();
$table = $this->getTable();
$sql .= "INSERT INTO ".$this->quoteIdentifier($this->getTable()->getName())." (";
// add column names to SQL
$colNames = array();
foreach ($row->getColumnValues() as $colValue) {
$colNames[] = $this->quoteIdentifier($colValue->getColumn()->getName());
}
$sql .= implode(',', $colNames);
$sql .= ") VALUES (";
$colVals = array();
foreach ($row->getColumnValues() as $colValue) {
$colVals[] = $this->getColumnValueSql($colValue);
}
$sql .= implode(',', $colVals);
$sql .= ");
";
return $sql;
}
/**
* Gets the propertly escaped (and quoted) value for a column.
* @param ColumnValue $colValue
* @return mixed The proper value to be added to the string.
*/
protected function getColumnValueSql(ColumnValue $colValue)
{
$column = $colValue->getColumn();
$method = 'get' . $column->getPhpNative() . 'Sql';
return $this->$method($colValue->getValue());
}
/**
* Gets a representation of a binary value suitable for use in a SQL statement.
* Default behavior is true = 1, false = 0.
* @param boolean $value
* @return int
*/
protected function getBooleanSql($value)
{
return (int) $value;
}
/**
* Gets a representation of a BLOB/LONGVARBINARY value suitable for use in a SQL statement.
* @param mixed $blob Blob object or string data.
* @return string
*/
protected function getBlobSql($blob)
{
// they took magic __toString() out of PHP5.0.0; this sucks
if (is_object($blob)) {
return $this->getPlatform()->quote($blob->__toString());
} else {
return $this->getPlatform()->quote($blob);
}
}
/**
* Gets a representation of a CLOB/LONGVARCHAR value suitable for use in a SQL statement.
* @param mixed $clob Clob object or string data.
* @return string
*/
protected function getClobSql($clob)
{
// they took magic __toString() out of PHP5.0.0; this sucks
if (is_object($clob)) {
return $this->getPlatform()->quote($clob->__toString());
} else {
return $this->getPlatform()->quote($clob);
}
}
/**
* Gets a representation of a date value suitable for use in a SQL statement.
* @param string $value
* @return string
*/
protected function getDateSql($value)
{
return "'" . date('Y-m-d', strtotime($value)) . "'";
}
/**
* Gets a representation of a decimal value suitable for use in a SQL statement.
* @param double $value
* @return float
*/
protected function getDecimalSql($value)
{
return (float) $value;
}
/**
* Gets a representation of a double value suitable for use in a SQL statement.
* @param double $value
* @return double
*/
protected function getDoubleSql($value)
{
return (double) $value;
}
/**
* Gets a representation of a float value suitable for use in a SQL statement.
* @param float $value
* @return float
*/
protected function getFloatSql($value)
{
return (float) $value;
}
/**
* Gets a representation of an integer value suitable for use in a SQL statement.
* @param int $value
* @return int
*/
protected function getIntSql($value)
{
return (int) $value;
}
/**
* Gets a representation of a NULL value suitable for use in a SQL statement.
* @return null
*/
protected function getNullSql()
{
return 'NULL';
}
/**
* Gets a representation of a string value suitable for use in a SQL statement.
* @param string $value
* @return string
*/
protected function getStringSql($value)
{
return $this->getPlatform()->quote($value);
}
/**
* Gets a representation of a time value suitable for use in a SQL statement.
* @param string $value
* @return string
*/
protected function getTimeSql($paramIndex, $value)
{
return "'" . date('H:i:s', strtotime($value)) . "'";
}
/**
* Gets a representation of a timestamp value suitable for use in a SQL statement.
* @param string $value
* @return string
*/
function getTimestampSql($value)
{
return "'" . date('Y-m-d H:i:s', strtotime($value)) . "'";
}
}

View file

@ -0,0 +1,173 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DDLBuilder.php';
/**
* The SQL DDL-building class for MS SQL Server.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.pgsql
*/
class MssqlDDLBuilder extends DDLBuilder
{
private static $dropCount = 0;
/**
*
* @see parent::addDropStatement()
*/
protected function addDropStatements(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getForeignKeys() as $fk) {
$script .= "
IF EXISTS (SELECT 1 FROM sysobjects WHERE type ='RI' AND name='".$fk->getName()."')
ALTER TABLE ".$this->quoteIdentifier($table->getName())." DROP CONSTRAINT ".$this->quoteIdentifier($fk->getName()).";
";
}
self::$dropCount++;
$script .= "
IF EXISTS (SELECT 1 FROM sysobjects WHERE type = 'U' AND name = '".$table->getName()."')
BEGIN
DECLARE @reftable_".self::$dropCount." nvarchar(60), @constraintname_".self::$dropCount." nvarchar(60)
DECLARE refcursor CURSOR FOR
select reftables.name tablename, cons.name constraintname
from sysobjects tables,
sysobjects reftables,
sysobjects cons,
sysreferences ref
where tables.id = ref.rkeyid
and cons.id = ref.constid
and reftables.id = ref.fkeyid
and tables.name = '".$table->getName()."'
OPEN refcursor
FETCH NEXT from refcursor into @reftable_".self::$dropCount.", @constraintname_".self::$dropCount."
while @@FETCH_STATUS = 0
BEGIN
exec ('alter table '+@reftable_".self::$dropCount."+' drop constraint '+@constraintname_".self::$dropCount.")
FETCH NEXT from refcursor into @reftable_".self::$dropCount.", @constraintname_".self::$dropCount."
END
CLOSE refcursor
DEALLOCATE refcursor
DROP TABLE ".$this->quoteIdentifier($table->getName())."
END
";
}
/**
* @see parent::addColumns()
*/
protected function addTable(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
/* ---------------------------------------------------------------------- */
/* ".$table->getName()." */
/* ---------------------------------------------------------------------- */
";
$this->addDropStatements($script);
$script .= "
CREATE TABLE ".$this->quoteIdentifier($table->getName())."
(
";
$lines = array();
foreach ($table->getColumns() as $col) {
$lines[] = $this->getColumnDDL($col);
}
if ($table->hasPrimaryKey()) {
$lines[] = "CONSTRAINT ".$this->quoteIdentifier($table->getName()."_PK") . " PRIMARY KEY (".$this->getColumnList($table->getPrimaryKey()).")";
}
foreach ($table->getUnices() as $unique ) {
$lines[] = "UNIQUE (".$this->getColumnList($unique->getColumns()).")";
}
$sep = ",
";
$script .= implode($sep, $lines);
$script .= "
);
";
}
/**
* Adds CREATE INDEX statements for this table.
* @see parent::addIndices()
*/
protected function addIndices(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getIndices() as $index) {
$script .= "
CREATE ";
if ($index->getIsUnique()) {
$script .= "UNIQUE";
}
$script .= "INDEX ".$this->quoteIdentifier($index->getName())." ON ".$this->quoteIdentifier($table->getName())." (".$this->getColumnList($index->getColumns()).");
";
}
}
/**
*
* @see parent::addForeignKeys()
*/
protected function addForeignKeys(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getForeignKeys() as $fk) {
$script .= "
BEGIN
ALTER TABLE ".$this->quoteIdentifier($table->getName())." ADD CONSTRAINT ".$this->quoteIdentifier($fk->getName())." FOREIGN KEY (".$this->getColumnList($fk->getLocalColumns()) .") REFERENCES ".$this->quoteIdentifier($fk->getForeignTableName())." (".$this->getColumnList($fk->getForeignColumns()).")";
if ($fk->hasOnUpdate()) {
if ($fk->getOnUpdate() == ForeignKey::SETNULL) { // there may be others that also won't work
// we have to skip this because it's unsupported.
$this->warn("MSSQL doesn't support the 'SET NULL' option for ON UPDATE (ignoring for ".$this->getColumnList($fk->getLocalColumns())." fk).");
} else {
$script .= " ON UPDATE ".$fk->getOnUpdate();
}
}
if ($fk->hasOnDelete()) {
if ($fk->getOnDelete() == ForeignKey::SETNULL) { // there may be others that also won't work
// we have to skip this because it's unsupported.
$this->warn("MSSQL doesn't support the 'SET NULL' option for ON DELETE (ignoring for ".$this->getColumnList($fk->getLocalColumns())." fk).");
} else {
$script .= " ON DELETE ".$fk->getOnDelete();
}
}
$script .= "
END
;
";
}
}
}

View file

@ -0,0 +1,37 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DataSQLBuilder.php';
/**
* MS SQL Server class for building data dump SQL.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.mssql
*/
class MssqlDataSQLBuilder extends DataSQLBuilder
{
/**
*
* @param mixed $blob Blob object or string containing data.
* @return string
*/
protected function getBlobSql($blob)
{
// they took magic __toString() out of PHP5.0.0; this sucks
if (is_object($blob)) {
$blob = $blob->__toString();
}
$data = unpack("H*hex", $blob);
return '0x'.$data['hex']; // no surrounding quotes!
}
}

View file

@ -0,0 +1,413 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DDLBuilder.php';
/**
* DDL Builder class for MySQL.
*
* @author David Z<EFBFBD>lke
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.mysql
*/
class MysqlDDLBuilder extends DDLBuilder
{
/**
* Returns some header SQL that disables foreign key checking.
* @return string DDL
*/
public static function getDatabaseStartDDL()
{
$ddl = "
# This is a fix for InnoDB in MySQL >= 4.1.x
# It \"suspends judgement\" for fkey relationships until are tables are set.
SET FOREIGN_KEY_CHECKS = 0;
";
return $ddl;
}
/**
* Returns some footer SQL that re-enables foreign key checking.
* @return string DDL
*/
public static function getDatabaseEndDDL()
{
$ddl = "
# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;
";
return $ddl;
}
/**
*
* @see parent::addDropStatement()
*/
protected function addDropStatements(&$script)
{
$script .= "
DROP TABLE IF EXISTS ".$this->quoteIdentifier($this->getTable()->getName()).";
";
}
/**
* Builds the SQL for current table and returns it as a string.
*
* This is the main entry point and defines a basic structure that classes should follow.
* In most cases this method will not need to be overridden by subclasses.
*
* @return string The resulting SQL DDL.
*/
public function build()
{
$script = "";
$this->addTable($script);
return $script;
}
/**
*
* @see parent::addColumns()
*/
protected function addTable(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
#-----------------------------------------------------------------------------
#-- ".$table->getName()."
#-----------------------------------------------------------------------------
";
$this->addDropStatements($script);
$script .= "
CREATE TABLE ".$this->quoteIdentifier($table->getName())."
(
";
$lines = array();
$databaseType = $this->getPlatform()->getDatabaseType();
foreach ($table->getColumns() as $col) {
$entry = $this->getColumnDDL($col);
$colinfo = $col->getVendorInfoForType($databaseType);
if ( $colinfo->hasParameter('Charset') ) {
$entry .= ' CHARACTER SET '.$platform->quote($colinfo->getParameter('Charset'));
}
if ( $colinfo->hasParameter('Collation') ) {
$entry .= ' COLLATE '.$platform->quote($colinfo->getParameter('Collation'));
} elseif ( $colinfo->hasParameter('Collate') ) {
$entry .= ' COLLATE '.$platform->quote($colinfo->getParameter('Collate'));
}
if ($col->getDescription()) {
$entry .= " COMMENT ".$platform->quote($col->getDescription());
}
$lines[] = $entry;
}
if ($table->hasPrimaryKey()) {
$lines[] = "PRIMARY KEY (".$this->getColumnList($table->getPrimaryKey()).")";
}
$this->addIndicesLines($lines);
$this->addForeignKeysLines($lines);
$sep = ",
";
$script .= implode($sep, $lines);
$script .= "
)";
$vendorSpecific = $table->getVendorInfoForType($this->getPlatform()->getDatabaseType());
if ($vendorSpecific->hasParameter('Type')) {
$mysqlTableType = $vendorSpecific->getParameter('Type');
} elseif ($vendorSpecific->hasParameter('Engine')) {
$mysqlTableType = $vendorSpecific->getParameter('Engine');
} else {
$mysqlTableType = $this->getBuildProperty("mysqlTableType");
}
$script .= sprintf(' %s=%s', $this->getBuildProperty("mysqlTableEngineKeyword"), $mysqlTableType);
$dbVendorSpecific = $table->getDatabase()->getVendorInfoForType($databaseType);
$tableVendorSpecific = $table->getVendorInfoForType($databaseType);
$vendorSpecific = $dbVendorSpecific->getMergedVendorInfo($tableVendorSpecific);
if ( $vendorSpecific->hasParameter('Charset') ) {
$script .= ' CHARACTER SET '.$platform->quote($vendorSpecific->getParameter('Charset'));
}
if ( $vendorSpecific->hasParameter('Collate') ) {
$script .= ' COLLATE '.$platform->quote($vendorSpecific->getParameter('Collate'));
}
if ( $vendorSpecific->hasParameter('Checksum') ) {
$script .= ' CHECKSUM='.$platform->quote($vendorSpecific->getParameter('Checksum'));
}
if ( $vendorSpecific->hasParameter('Pack_Keys') ) {
$script .= ' PACK_KEYS='.$platform->quote($vendorSpecific->getParameter('Pack_Keys'));
}
if ( $vendorSpecific->hasParameter('Delay_key_write') ) {
$script .= ' DELAY_KEY_WRITE='.$platform->quote($vendorSpecific->getParameter('Delay_key_write'));
}
if ($table->getDescription()) {
$script .= " COMMENT=".$platform->quote($table->getDescription());
}
$script .= ";
";
}
/**
* Creates a comma-separated list of column names for the index.
* For MySQL unique indexes there is the option of specifying size, so we cannot simply use
* the getColumnsList() method.
* @param Index $index
* @return string
*/
private function getIndexColumnList(Index $index)
{
$platform = $this->getPlatform();
$cols = $index->getColumns();
$list = array();
foreach ($cols as $col) {
$list[] = $this->quoteIdentifier($col) . ($index->hasColumnSize($col) ? '(' . $index->getColumnSize($col) . ')' : '');
}
return implode(', ', $list);
}
/**
* Adds indexes
*/
protected function addIndicesLines(&$lines)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getUnices() as $unique) {
$lines[] = "UNIQUE KEY ".$this->quoteIdentifier($unique->getName())." (".$this->getIndexColumnList($unique).")";
}
foreach ($table->getIndices() as $index ) {
$vendorInfo = $index->getVendorInfoForType($platform->getDatabaseType());
$lines[] .= (($vendorInfo && $vendorInfo->getParameter('Index_type') == 'FULLTEXT') ? 'FULLTEXT ' : '') . "KEY " . $this->quoteIdentifier($index->getName()) . "(" . $this->getIndexColumnList($index) . ")";
}
}
/**
* Adds foreign key declarations & necessary indexes for mysql (if they don't exist already).
* @see parent::addForeignKeys()
*/
protected function addForeignKeysLines(&$lines)
{
$table = $this->getTable();
$platform = $this->getPlatform();
/**
* A collection of indexed columns. The keys is the column name
* (concatenated with a comma in the case of multi-col index), the value is
* an array with the names of the indexes that index these columns. We use
* it to determine which additional indexes must be created for foreign
* keys. It could also be used to detect duplicate indexes, but this is not
* implemented yet.
* @var array
*/
$_indices = array();
$this->collectIndexedColumns('PRIMARY', $table->getPrimaryKey(), $_indices, 'getName');
$_tableIndices = array_merge($table->getIndices(), $table->getUnices());
foreach ($_tableIndices as $_index) {
$this->collectIndexedColumns($_index->getName(), $_index->getColumns(), $_indices);
}
// we're determining which tables have foreign keys that point to this table, since MySQL needs an index on
// any column that is referenced by another table (yep, MySQL _is_ a PITA)
$counter = 0;
$allTables = $table->getDatabase()->getTables();
foreach ($allTables as $_table) {
foreach ($_table->getForeignKeys() as $_foreignKey) {
if ($_foreignKey->getForeignTableName() == $table->getName()) {
$referencedColumns = $_foreignKey->getForeignColumns();
$referencedColumnsHash = $this->getColumnList($referencedColumns);
if (!array_key_exists($referencedColumnsHash, $_indices)) {
// no matching index defined in the schema, so we have to create one
$indexName = "I_referenced_".$_foreignKey->getName()."_".(++$counter);
$lines[] = "INDEX ".$this->quoteIdentifier($indexName)." (" .$referencedColumnsHash.")";
// Add this new index to our collection, otherwise we might add it again (bug #725)
$this->collectIndexedColumns($indexName, $referencedColumns, $_indices);
}
}
}
}
foreach ($table->getForeignKeys() as $fk) {
$indexName = $this->quoteIdentifier(substr_replace($fk->getName(), 'FI_', strrpos($fk->getName(), 'FK_'), 3));
$localColumns = $fk->getLocalColumns();
$localColumnsHash = $this->getColumnList($localColumns);
if (!array_key_exists($localColumnsHash, $_indices)) {
// no matching index defined in the schema, so we have to create one. MySQL needs indices on any columns that serve as foreign keys. these are not auto-created prior to 4.1.2
$lines[] = "INDEX $indexName (".$localColumnsHash.")";
$this->collectIndexedColumns($indexName, $localColumns, $_indices);
}
$str = "CONSTRAINT ".$this->quoteIdentifier($fk->getName())."
FOREIGN KEY (".$this->getColumnList($fk->getLocalColumns()).")
REFERENCES ".$this->quoteIdentifier($fk->getForeignTableName()) . " (".$this->getColumnList($fk->getForeignColumns()).")";
if ($fk->hasOnUpdate()) {
$str .= "
ON UPDATE ".$fk->getOnUpdate();
}
if ($fk->hasOnDelete()) {
$str .= "
ON DELETE ".$fk->getOnDelete();
}
$lines[] = $str;
}
}
/**
* Helper function to collect indexed columns.
* @param array $columns The column names, or objects with a $callback method
* @param array $indexedColumns The collected indexes
* @param string $callback The name of a method to call on each of $columns to get the column name, if needed.
* @return unknown_type
*/
private function collectIndexedColumns($indexName, $columns, &$collectedIndexes, $callback = null)
{
// Get the actual column names, using the callback if needed.
// DDLBuilder::getColumnList tests $col instanceof Column, and no callback - maybe we should too?
$colnames = $columns;
if ($callback) {
$colnames = array();
foreach ($columns as $col) {
$colnames[] = $col->$callback();
}
}
/**
* "If the table has a multiple-column index, any leftmost prefix of the
* index can be used by the optimizer to find rows. For example, if you
* have a three-column index on (col1, col2, col3), you have indexed search
* capabilities on (col1), (col1, col2), and (col1, col2, col3)."
* @link http://dev.mysql.com/doc/refman/5.5/en/mysql-indexes.html
*/
$indexedColumns = array();
foreach ($colnames as $colname) {
$indexedColumns[] = $this->quoteIdentifier($colname);
$indexedColumnsHash = implode(',', $indexedColumns);
if (!array_key_exists($indexedColumnsHash, $collectedIndexes)) {
$collectedIndexes[$indexedColumnsHash] = array();
}
$collectedIndexes[$indexedColumnsHash][] = $indexName;
}
}
/**
* Checks whether passed-in array of Column objects contains a column with specified name.
* @param array Column[] or string[]
* @param string $searchcol Column name to search for
*/
private function containsColname($columns, $searchcol)
{
foreach ($columns as $col) {
if ($col instanceof Column) {
$col = $col->getName();
}
if ($col == $searchcol) {
return true;
}
}
return false;
}
/**
* Not used for MySQL since foreign keys are declared inside table declaration.
* @see addForeignKeysLines()
*/
protected function addForeignKeys(&$script)
{
}
/**
* Not used for MySQL since indexes are declared inside table declaration.
* @see addIndicesLines()
*/
protected function addIndices(&$script)
{
}
/**
* Builds the DDL SQL for a Column object.
* @return string
*/
public function getColumnDDL(Column $col)
{
$platform = $this->getPlatform();
$domain = $col->getDomain();
$sqlType = $domain->getSqlType();
$notNullString = $col->getNotNullString();
$defaultSetting = $col->getDefaultSetting();
// Special handling of TIMESTAMP/DATETIME types ...
// See: http://propel.phpdb.org/trac/ticket/538
if ($sqlType == 'DATETIME') {
$def = $domain->getDefaultValue();
if ($def && $def->isExpression()) { // DATETIME values can only have constant expressions
$sqlType = 'TIMESTAMP';
}
} elseif ($sqlType == 'DATE') {
$def = $domain->getDefaultValue();
if ($def && $def->isExpression()) {
throw new EngineException("DATE columns cannot have default *expressions* in MySQL.");
}
} elseif ($sqlType == 'TEXT' || $sqlType == 'BLOB') {
if ($domain->getDefaultValue()) {
throw new EngineException("BLOB and TEXT columns cannot have DEFAULT values. in MySQL.");
}
}
$sb = "";
$sb .= $this->quoteIdentifier($col->getName()) . " ";
$sb .= $sqlType;
if ($platform->hasSize($sqlType)) {
$sb .= $domain->printSize();
}
$sb .= " ";
if ($sqlType == 'TIMESTAMP') {
$notNullString = $col->getNotNullString();
$defaultSetting = $col->getDefaultSetting();
if ($notNullString == '') {
$notNullString = 'NULL';
}
if ($defaultSetting == '' && $notNullString == 'NOT NULL') {
$defaultSetting = 'DEFAULT CURRENT_TIMESTAMP';
}
$sb .= $notNullString . " " . $defaultSetting . " ";
} else {
$sb .= $defaultSetting . " ";
$sb .= $notNullString . " ";
}
$sb .= $col->getAutoIncrementString();
return trim($sb);
}
}

View file

@ -0,0 +1,22 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DataSQLBuilder.php';
/**
* MySQL class for building data dump SQL.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.mysql
*/
class MysqlDataSQLBuilder extends DataSQLBuilder
{
}

View file

@ -0,0 +1,185 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DDLBuilder.php';
/**
* The SQL DDL-building class for Oracle.
*
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.pgsql
*/
class OracleDDLBuilder extends DDLBuilder
{
/**
* This function adds any _database_ start/initialization SQL.
* This is designed to be called for a database, not a specific table, hence it is static.
* @see parent::getDatabaseStartDDL()
*
* @return string The DDL is returned as astring.
*/
public static function getDatabaseStartDDL()
{
return "
ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS';
";
}
/**
*
* @see parent::addDropStatement()
*/
protected function addDropStatements(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
DROP TABLE ".$this->quoteIdentifier($table->getName())." CASCADE CONSTRAINTS;
";
if ($table->getIdMethod() == "native") {
$script .= "
DROP SEQUENCE ".$this->quoteIdentifier($this->getSequenceName()).";
";
}
}
/**
*
* @see parent::addColumns()
*/
protected function addTable(&$script)
{
$table = $this->getTable();
$script .= "
-----------------------------------------------------------------------
-- ".$table->getName()."
-----------------------------------------------------------------------
";
$this->addDropStatements($script);
$script .= "
CREATE TABLE ".$this->quoteIdentifier($table->getName())."
(
";
$lines = array();
foreach ($table->getColumns() as $col) {
$lines[] = $this->getColumnDDL($col);
}
$sep = ",
";
$script .= implode($sep, $lines);
$script .= "
);
";
$this->addPrimaryKey($script);
$this->addSequences($script);
}
/**
*
*
*/
protected function addPrimaryKey(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$tableName = $table->getName();
$length = strlen($tableName);
if ($length > 27) {
$length = 27;
}
if ( is_array($table->getPrimaryKey()) && count($table->getPrimaryKey()) ) {
$script .= "
ALTER TABLE ".$this->quoteIdentifier($table->getName())."
ADD CONSTRAINT ".$this->quoteIdentifier(substr($tableName,0,$length)."_PK")."
PRIMARY KEY (";
$delim = "";
foreach ($table->getPrimaryKey() as $col) {
$script .= $delim . $this->quoteIdentifier($col->getName());
$delim = ",";
}
$script .= ");
";
}
}
/**
* Adds CREATE SEQUENCE statements for this table.
*
*/
protected function addSequences(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
if ($table->getIdMethod() == "native") {
$script .= "
CREATE SEQUENCE ".$this->quoteIdentifier($this->getSequenceName())."
INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE NOCACHE ORDER;
";
}
}
/**
* Adds CREATE INDEX statements for this table.
* @see parent::addIndices()
*/
protected function addIndices(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getIndices() as $index) {
$script .= "
CREATE ";
if ($index->getIsUnique()) {
$script .= "UNIQUE";
}
$script .= "INDEX ".$this->quoteIdentifier($index->getName()) ." ON ".$this->quoteIdentifier($table->getName())." (".$this->getColumnList($index->getColumns()).");
";
}
}
/**
*
* @see parent::addForeignKeys()
*/
protected function addForeignKeys(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getForeignKeys() as $fk) {
$script .= "
ALTER TABLE ".$this->quoteIdentifier($table->getName())."
ADD CONSTRAINT ".$this->quoteIdentifier($fk->getName())."
FOREIGN KEY (".$this->getColumnList($fk->getLocalColumns()) .") REFERENCES ".$this->quoteIdentifier($fk->getForeignTableName())." (".$this->getColumnList($fk->getForeignColumns()).")";
if ($fk->hasOnUpdate()) {
$this->warn("ON UPDATE not yet implemented for Oracle builder.(ignoring for ".$this->getColumnList($fk->getLocalColumns())." fk).");
//$script .= " ON UPDATE ".$fk->getOnUpdate();
}
if ($fk->hasOnDelete()) {
$script .= "
ON DELETE ".$fk->getOnDelete();
}
$script .= ";
";
}
}
}

View file

@ -0,0 +1,22 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DataSQLBuilder.php';
/**
* Oracle class for building data dump SQL.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.oracle
*/
class OracleDataSQLBuilder extends DataSQLBuilder
{
}

View file

@ -0,0 +1,304 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DDLBuilder.php';
/**
* The SQL DDL-building class for PostgreSQL.
*
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.pgsql
*/
class PgsqlDDLBuilder extends DDLBuilder
{
/**
* Array that keeps track of already
* added schema names
*
* @var Array of schema names
*/
protected static $addedSchemas = array();
/**
* Queue of constraint SQL that will be added to script at the end.
*
* PostgreSQL seems (now?) to not like constraints for tables that don't exist,
* so the solution is to queue up the statements and execute it at the end.
*
* @var array
*/
protected static $queuedConstraints = array();
/**
* Reset static vars between db iterations.
*/
public static function reset()
{
self::$addedSchemas = array();
self::$queuedConstraints = array();
}
/**
* Returns all the ALTER TABLE ADD CONSTRAINT lines for inclusion at end of file.
* @return string DDL
*/
public static function getDatabaseEndDDL()
{
$ddl = implode("", self::$queuedConstraints);
return $ddl;
}
/**
* Get the schema for the current table
*
* @author Markus Lervik <markus.lervik@necora.fi>
* @access protected
* @return schema name if table has one, else
* null
**/
protected function getSchema()
{
$table = $this->getTable();
$vi = $table->getVendorInfoForType($this->getPlatform()->getDatabaseType());
if ($vi->hasParameter('schema')) {
return $vi->getParameter('schema');
}
return null;
}
/**
* Add a schema to the generated SQL script
*
* @author Markus Lervik <markus.lervik@necora.fi>
* @access protected
* @return string with CREATE SCHEMA statement if
* applicable, else empty string
**/
protected function addSchema()
{
$schemaName = $this->getSchema();
if ($schemaName !== null) {
if (!in_array($schemaName, self::$addedSchemas)) {
$platform = $this->getPlatform();
self::$addedSchemas[] = $schemaName;
return "\nCREATE SCHEMA " . $this->quoteIdentifier($schemaName) . ";\n";
}
}
return '';
}
/**
*
* @see parent::addDropStatement()
*/
protected function addDropStatements(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
DROP TABLE ".$this->quoteIdentifier($table->getName())." CASCADE;
";
if ($table->getIdMethod() == IDMethod::NATIVE && $table->getIdMethodParameters()) {
$script .= "
DROP SEQUENCE ".$this->quoteIdentifier(strtolower($this->getSequenceName())).";
";
}
}
/**
*
* @see parent::addColumns()
*/
protected function addTable(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
-----------------------------------------------------------------------------
-- ".$table->getName()."
-----------------------------------------------------------------------------
";
$script .= $this->addSchema();
$schemaName = $this->getSchema();
if ($schemaName !== null) {
$script .= "\nSET search_path TO " . $this->quoteIdentifier($schemaName) . ";\n";
}
$this->addDropStatements($script);
$this->addSequences($script);
$script .= "
CREATE TABLE ".$this->quoteIdentifier($table->getName())."
(
";
$lines = array();
foreach ($table->getColumns() as $col) {
/* @var $col Column */
$colDDL = $this->getColumnDDL($col);
if ($col->isAutoIncrement() && $table->getIdMethodParameters() == null) {
if ($col->getType() === PropelTypes::BIGINT) {
$colDDL = str_replace($col->getDomain()->getSqlType(), 'bigserial', $colDDL);
} else {
$colDDL = str_replace($col->getDomain()->getSqlType(), 'serial', $colDDL);
}
}
$lines[] = $colDDL;
}
if ($table->hasPrimaryKey()) {
$lines[] = "PRIMARY KEY (".$this->getColumnList($table->getPrimaryKey()).")";
}
foreach ($table->getUnices() as $unique ) {
$lines[] = "CONSTRAINT ".$this->quoteIdentifier($unique->getName())." UNIQUE (".$this->getColumnList($unique->getColumns()).")";
}
$sep = ",
";
$script .= implode($sep, $lines);
$script .= "
);
COMMENT ON TABLE ".$this->quoteIdentifier($table->getName())." IS " . $platform->quote($table->getDescription()).";
";
$this->addColumnComments($script);
$script .= "\nSET search_path TO public;";
}
/**
* Adds comments for the columns.
*
*/
protected function addColumnComments(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($this->getTable()->getColumns() as $col) {
if ( $col->getDescription() != '' ) {
$script .= "
COMMENT ON COLUMN ".$this->quoteIdentifier($table->getName()).".".$this->quoteIdentifier($col->getName())." IS ".$platform->quote($col->getDescription()) .";
";
}
}
}
/**
* Override to provide sequence names that conform to postgres' standard when
* no id-method-parameter specified.
*
* @see DataModelBuilder::getSequenceName()
* @return string
*/
public function getSequenceName()
{
$table = $this->getTable();
static $longNamesMap = array();
$result = null;
if ($table->getIdMethod() == IDMethod::NATIVE) {
$idMethodParams = $table->getIdMethodParameters();
if (empty($idMethodParams)) {
$result = null;
// We're going to ignore a check for max length (mainly
// because I'm not sure how Postgres would handle this w/ SERIAL anyway)
foreach ($table->getColumns() as $col) {
if ($col->isAutoIncrement()) {
$result = $table->getName() . '_' . $col->getName() . '_seq';
break; // there's only one auto-increment column allowed
}
}
} else {
$result = $idMethodParams[0]->getValue();
}
}
return $result;
}
/**
* Adds CREATE SEQUENCE statements for this table.
*
*/
protected function addSequences(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
if ($table->getIdMethod() == IDMethod::NATIVE && $table->getIdMethodParameters() != null) {
$script .= "
CREATE SEQUENCE ".$this->quoteIdentifier(strtolower($this->getSequenceName())).";
";
}
}
/**
* Adds CREATE INDEX statements for this table.
* @see parent::addIndices()
*/
protected function addIndices(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getIndices() as $index) {
$script .= "
CREATE ";
if ($index->getIsUnique()) {
$script .= "UNIQUE";
}
$script .= "INDEX ".$this->quoteIdentifier($index->getName())." ON ".$this->quoteIdentifier($table->getName())." (".$this->getColumnList($index->getColumns()).");
";
}
}
/**
*
* @see parent::addForeignKeys()
*/
protected function addForeignKeys(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getForeignKeys() as $fk) {
$privscript = "
ALTER TABLE ".$this->quoteIdentifier($table->getName())." ADD CONSTRAINT ".$this->quoteIdentifier($fk->getName())." FOREIGN KEY (".$this->getColumnList($fk->getLocalColumns()) .") REFERENCES ".$this->quoteIdentifier($fk->getForeignTableName())." (".$this->getColumnList($fk->getForeignColumns()).")";
if ($fk->hasOnUpdate()) {
$privscript .= " ON UPDATE ".$fk->getOnUpdate();
}
if ($fk->hasOnDelete()) {
$privscript .= " ON DELETE ".$fk->getOnDelete();
}
$privscript .= ";
";
self::$queuedConstraints[] = $privscript;
}
}
}

View file

@ -0,0 +1,102 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DataSQLBuilder.php';
/**
* PostgreSQL class for building data dump SQL.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.pgsql
*/
class PgsqlDataSQLBuilder extends DataSQLBuilder
{
/**
* The largets serial value encountered this far.
*
* @var int
*/
private $maxSeqVal;
/**
* Construct a new PgsqlDataSQLBuilder object.
*
* @param Table $table
*/
public function __construct(Table $table)
{
parent::__construct($table);
}
/**
* The main method in this class, returns the SQL for INSERTing data into a row.
* @param DataRow $row The row to process.
* @return string
*/
public function buildRowSql(DataRow $row)
{
$sql = parent::buildRowSql($row);
$table = $this->getTable();
if ($table->hasAutoIncrementPrimaryKey() && $table->getIdMethod() == IDMethod::NATIVE) {
foreach ($row->getColumnValues() as $colValue) {
if ($colValue->getColumn()->isAutoIncrement()) {
if ($colValue->getValue() > $this->maxSeqVal) {
$this->maxSeqVal = $colValue->getValue();
}
}
}
}
return $sql;
}
public function getTableEndSql()
{
$table = $this->getTable();
$sql = "";
if ($table->hasAutoIncrementPrimaryKey() && $table->getIdMethod() == IDMethod::NATIVE) {
$seqname = $this->getDDLBuilder()->getSequenceName();
$sql .= "SELECT pg_catalog.setval('$seqname', ".((int)$this->maxSeqVal).");
";
}
return $sql;
}
/**
* Get SQL value to insert for Postgres BOOLEAN column.
* @param boolean $value
* @return string The representation of boolean for Postgres ('t' or 'f').
*/
protected function getBooleanSql($value)
{
if ($value === 'f' || $value === 'false' || $value === "0") {
$value = false;
}
return ($value ? "'t'" : "'f'");
}
/**
*
* @param mixed $blob Blob object or string containing data.
* @return string
*/
protected function getBlobSql($blob)
{
// they took magic __toString() out of PHP5.0.0; this sucks
if (is_object($blob)) {
$blob = $blob->__toString();
}
return "'" . pg_escape_bytea($blob) . "'";
}
}

View file

@ -0,0 +1,119 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DDLBuilder.php';
/**
* The SQL DDL-building class for SQLite.
*
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.pgsql
*/
class SqliteDDLBuilder extends DDLBuilder
{
/**
*
* @see parent::addDropStatement()
*/
protected function addDropStatements(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
DROP TABLE ".$this->quoteIdentifier($table->getName()).";
";
}
/**
*
* @see parent::addColumns()
*/
protected function addTable(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
$script .= "
-----------------------------------------------------------------------------
-- ".$table->getName()."
-----------------------------------------------------------------------------
";
$this->addDropStatements($script);
$script .= "
CREATE TABLE ".$this->quoteIdentifier($table->getName())."
(
";
$lines = array();
foreach ($table->getColumns() as $col) {
$lines[] = $this->getColumnDDL($col);
}
if ($table->hasPrimaryKey() && count($table->getPrimaryKey()) > 1) {
$lines[] = "PRIMARY KEY (".$this->getColumnList($table->getPrimaryKey()).")";
}
foreach ($table->getUnices() as $unique ) {
$lines[] = "UNIQUE (".$this->getColumnList($unique->getColumns()).")";
}
$sep = ",
";
$script .= implode($sep, $lines);
$script .= "
);
";
}
/**
* Adds CREATE INDEX statements for this table.
* @see parent::addIndices()
*/
protected function addIndices(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getIndices() as $index) {
$script .= "
CREATE ";
if ($index->getIsUnique()) {
$script .= "UNIQUE";
}
$script .= "INDEX ".$this->quoteIdentifier($index->getName())." ON ".$this->quoteIdentifier($table->getName())." (".$this->getColumnList($index->getColumns()).");
";
}
}
/**
*
* @see parent::addForeignKeys()
*/
protected function addForeignKeys(&$script)
{
$table = $this->getTable();
$platform = $this->getPlatform();
foreach ($table->getForeignKeys() as $fk) {
$script .= "
-- SQLite does not support foreign keys; this is just for reference
-- FOREIGN KEY (".$this->getColumnList($fk->getLocalColumns()).") REFERENCES ".$fk->getForeignTableName()." (".$this->getColumnList($fk->getForeignColumns()).")
";
}
}
}

View file

@ -0,0 +1,36 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/sql/DataSQLBuilder.php';
/**
* SQLite class for building data dump SQL.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.builder.sql.sqlite
*/
class SqliteDataSQLBuilder extends DataSQLBuilder
{
/**
* Returns string processed by sqlite_udf_encode_binary() to ensure that binary contents will be handled correctly by sqlite.
* @param mixed $blob Blob or string
* @return string encoded text
*/
protected function getBlobSql($blob)
{
// they took magic __toString() out of PHP5.0.0; this sucks
if (is_object($blob)) {
$blob = $blob->__toString();
}
return "'" . sqlite_udf_encode_binary($blob) . "'";
}
}

View file

@ -0,0 +1,33 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'builder/util/Pluralizer.php';
/**
* The default Enlglish pluralizer class.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1612 $
* @package propel.generator.builder.util
*/
class DefaultEnglishPluralizer implements Pluralizer
{
/**
* Generate a plural name based on the passed in root.
* @param string $root The root that needs to be pluralized (e.g. Author)
* @return string The plural form of $root (e.g. Authors).
*/
public function getPluralForm($root)
{
return $root . 's';
}
}

View file

@ -0,0 +1,28 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* The generic interface to create a plural form of a name.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1612 $
* @package propel.generator.builder.util
*/
interface Pluralizer
{
/**
* Generate a plural name based on the passed in root.
* @param string $root The root that needs to be pluralized (e.g. Author)
* @return string The plural form of $root.
*/
public function getPluralForm($root);
}

View file

@ -0,0 +1,91 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
include_once 'phing/system/io/Reader.php';
/**
* Overrides Phing's StringReader to allow inclusin inside a BufferedReader
*
* @author François Zaninotto
* @version $Revision: 1785 $
* @package propel.generator.builder.util
*/
class PropelStringReader extends Reader
{
/**
* @var string
*/
protected $_string;
/**
* @var int
*/
protected $mark = 0;
/**
* @var int
*/
protected $currPos = 0;
public function __construct($string)
{
$this->_string = $string;
}
public function skip($n)
{
$this->currPos = $this->currPos + $n;
}
public function eof()
{
return $this->currPos == strlen($this->_string);
}
public function read($len = null)
{
if ($len === null) {
return $this->_string;
} else {
if ($this->currPos >= strlen($this->_string)) {
return -1;
}
$out = substr($this->_string, $this->currPos, $len);
$this->currPos += $len;
return $out;
}
}
public function mark()
{
$this->mark = $this->currPos;
}
public function reset()
{
$this->currPos = $this->mark;
}
public function close() {}
public function open() {}
public function ready() {}
public function markSupported()
{
return true;
}
public function getResource()
{
return '(string) "'.$this->_string . '"';
}
}

View file

@ -0,0 +1,92 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Simple templating system to ease behavior writing
*
* @author François Zaninotto
* @version $Revision: 1784 $
* @package propel.generator.builder.util
*/
class PropelTemplate
{
protected $template, $templateFile;
/**
* Set a string as a template.
* The string doesn't need closing php tags.
*
* <code>
* $template->setTemplate('This is <?php echo $name ?>');
* </code>
*
* @param string $template the template string
*/
public function setTemplate($template)
{
$this->template = $template;
}
/**
* Set a file as a template. The file can be any regular PHP file.
*
* <code>
* $template->setTemplateFile(dirname(__FILE__) . '/template/foo.php');
* </code>
*
* @param string $filePath The (absolute or relative to the include path) file path
*/
public function setTemplateFile($filePath)
{
$this->templateFile = $filePath;
}
/**
* Render the template using the variable provided as arguments.
*
* <code>
* $template = new PropelTemplate();
* $template->setTemplate('This is <?php echo $name ?>');
* echo $template->render(array('name' => 'Mike'));
* // This is Mike
* </code>
*
* @param array $vars An associative array of argumens to be rendered
*
* @return string The rendered template
*/
public function render($vars = array())
{
if (null === $this->templateFile && null === $this->template) {
throw new InvalidArgumentException('You must set a template or a template file before rendering');
}
extract($vars);
ob_start();
ob_implicit_flush(0);
try
{
if (null !== $this->templateFile) {
require($this->templateFile);
} else {
eval('?>' . $this->template . '<?php ');
}
}
catch (Exception $e)
{
// need to end output buffering before throwing the exception #7596
ob_end_clean();
throw $e;
}
return ob_get_clean();
}
}

View file

@ -0,0 +1,417 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/AppData.php';
// Phing dependencies
require_once 'phing/parser/AbstractHandler.php';
require_once 'builder/util/PropelStringReader.php';
/**
* A class that is used to parse an input xml schema file and creates an AppData
* PHP object.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Leon Messerschmidt <leon@opticode.co.za> (Torque)
* @author Jason van Zyl <jvanzyl@apache.org> (Torque)
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @author Daniel Rall <dlr@collab.net> (Torque)
* @version $Revision: 1764 $
* @package propel.generator.builder.util
*/
class XmlToAppData extends AbstractHandler
{
/** enables debug output */
const DEBUG = false;
private $app;
private $platform;
private $currDB;
private $currTable;
private $currColumn;
private $currFK;
private $currIndex;
private $currUnique;
private $currValidator;
private $currBehavior;
private $currVendorObject;
private $isForReferenceOnly;
private $currentPackage;
private $currentXmlFile;
private $defaultPackage;
private $encoding;
/** two-dimensional array,
first dimension is for schemas(key is the path to the schema file),
second is for tags within the schema */
private $schemasTagsStack = array();
public $parser;
/**
* Creates a new instance for the specified database type.
*
* @param Platform $platform The type of database for the application.
* @param string $defaultPackage the default PHP package used for the om
* @param string $encoding The database encoding.
*/
public function __construct(Platform $platform, $defaultPackage, $encoding = 'iso-8859-1')
{
$this->app = new AppData($platform);
$this->platform = $platform;
$this->defaultPackage = $defaultPackage;
$this->firstPass = true;
$this->encoding = $encoding;
}
/**
* Parses a XML input file and returns a newly created and
* populated AppData structure.
*
* @param string $xmlFile The input file to parse.
* @return AppData populated by <code>xmlFile</code>.
*/
public function parseFile($xmlFile)
{
// we don't want infinite recursion
if ($this->isAlreadyParsed($xmlFile)) {
return;
}
$f = new PhingFile($xmlFile);
return $this->parseString($f->contents(), $xmlFile);
}
/**
* Parses a XML input string and returns a newly created and
* populated AppData structure.
*
* @param string $xmlString The input string to parse.
* @param string $xmlFile The input file name.
* @return AppData populated by <code>xmlFile</code>.
*/
public function parseString($xmlString, $xmlFile)
{
// we don't want infinite recursion
if ($this->isAlreadyParsed($xmlFile)) {
return;
}
// store current schema file path
$this->schemasTagsStack[$xmlFile] = array();
$this->currentXmlFile = $xmlFile;
try {
$sr = new PropelStringReader($xmlString);
} catch (Exception $e) {
$f = new PhingFile($xmlFile);
throw new Exception("XML File not found: " . $f->getAbsolutePath());
}
$br = new BufferedReader($sr);
$this->parser = new ExpatParser($br);
$this->parser->parserSetOption(XML_OPTION_CASE_FOLDING, 0);
$this->parser->setHandler($this);
try {
$this->parser->parse();
} catch (Exception $e) {
$br->close();
throw $e;
}
$br->close();
array_pop($this->schemasTagsStack);
return $this->app;
}
/**
* Handles opening elements of the xml file.
*
* @param string $uri
* @param string $localName The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
* @param string $rawName The qualified name (with prefix), or the empty string if
* qualified names are not available.
* @param string $attributes The specified or defaulted attributes
*/
public function startElement($name, $attributes) {
try {
$parentTag = $this->peekCurrentSchemaTag();
if ($parentTag === false) {
switch($name) {
case "database":
if ($this->isExternalSchema()) {
$this->currentPackage = @$attributes["package"];
if ($this->currentPackage === null) {
$this->currentPackage = $this->defaultPackage;
}
} else {
$this->currDB = $this->app->addDatabase($attributes);
}
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "database") {
switch($name) {
case "external-schema":
$xmlFile = @$attributes["filename"];
//"referenceOnly" attribute is valid in the main schema XML file only,
//and it's ingnored in the nested external-schemas
if (!$this->isExternalSchema()) {
$isForRefOnly = @$attributes["referenceOnly"];
$this->isForReferenceOnly = ($isForRefOnly !== null ? (strtolower($isForRefOnly) === "true") : true); // defaults to TRUE
}
if ($xmlFile{0} != '/') {
$f = new PhingFile($this->currentXmlFile);
$xf = new PhingFile($f->getParent(), $xmlFile);
$xmlFile = $xf->getPath();
}
$this->parseFile($xmlFile);
break;
case "domain":
$this->currDB->addDomain($attributes);
break;
case "table":
$this->currTable = $this->currDB->addTable($attributes);
if ($this->isExternalSchema()) {
$this->currTable->setForReferenceOnly($this->isForReferenceOnly);
$this->currTable->setPackage($this->currentPackage);
}
break;
case "vendor":
$this->currVendorObject = $this->currDB->addVendorInfo($attributes);
break;
case "behavior":
$this->currBehavior = $this->currDB->addBehavior($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "table") {
switch($name) {
case "column":
$this->currColumn = $this->currTable->addColumn($attributes);
break;
case "foreign-key":
$this->currFK = $this->currTable->addForeignKey($attributes);
break;
case "index":
$this->currIndex = $this->currTable->addIndex($attributes);
break;
case "unique":
$this->currUnique = $this->currTable->addUnique($attributes);
break;
case "vendor":
$this->currVendorObject = $this->currTable->addVendorInfo($attributes);
break;
case "validator":
$this->currValidator = $this->currTable->addValidator($attributes);
break;
case "id-method-parameter":
$this->currTable->addIdMethodParameter($attributes);
break;
case "behavior":
$this->currBehavior = $this->currTable->addBehavior($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "column") {
switch($name) {
case "inheritance":
$this->currColumn->addInheritance($attributes);
break;
case "vendor":
$this->currVendorObject = $this->currColumn->addVendorInfo($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "foreign-key") {
switch($name) {
case "reference":
$this->currFK->addReference($attributes);
break;
case "vendor":
$this->currVendorObject = $this->currUnique->addVendorInfo($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "index") {
switch($name) {
case "index-column":
$this->currIndex->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = $this->currIndex->addVendorInfo($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "unique") {
switch($name) {
case "unique-column":
$this->currUnique->addColumn($attributes);
break;
case "vendor":
$this->currVendorObject = $this->currUnique->addVendorInfo($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "behavior") {
switch($name) {
case "parameter":
$this->currBehavior->addParameter($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "validator") {
switch($name) {
case "rule":
$this->currValidator->addRule($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} elseif ($parentTag == "vendor") {
switch($name) {
case "parameter":
$this->currVendorObject->addParameter($attributes);
break;
default:
$this->_throwInvalidTagException($name);
}
} else {
// it must be an invalid tag
$this->_throwInvalidTagException($name);
}
$this->pushCurrentSchemaTag($name);
} catch (BuildException $e) {
throw $e;
} catch (Exception $e) {
echo $e;
echo "\n";
throw $e;
}
}
function _throwInvalidTagException($tag_name)
{
throw new BuildException("Unexpected tag <" . $tag_name . ">", $this->parser->getLocation());
}
/**
* Handles closing elements of the xml file.
*
* @param uri
* @param localName The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
* @param rawName The qualified name (with prefix), or the empty string if
* qualified names are not available.
*/
public function endElement($name)
{
if (self::DEBUG) {
print("endElement(" . $name . ") called\n");
}
$this->popCurrentSchemaTag();
}
protected function peekCurrentSchemaTag()
{
$keys = array_keys($this->schemasTagsStack);
return end($this->schemasTagsStack[end($keys)]);
}
protected function popCurrentSchemaTag()
{
$keys = array_keys($this->schemasTagsStack);
array_pop($this->schemasTagsStack[end($keys)]);
}
protected function pushCurrentSchemaTag($tag)
{
$keys = array_keys($this->schemasTagsStack);
$this->schemasTagsStack[end($keys)][] = $tag;
}
protected function isExternalSchema()
{
return count($this->schemasTagsStack) > 1;
}
protected function isAlreadyParsed($filePath)
{
return isset($this->schemasTagsStack[$filePath]);
}
}

View file

@ -0,0 +1,265 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'phing/parser/AbstractHandler.php';
/**
* A Class that is used to parse an data dump XML file and create SQL using a DataSQLBuilder class.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @version $Revision: 1612 $
* @package propel.generator.builder.util
*/
class XmlToDataSQL extends AbstractHandler
{
/**
* The GeneratorConfig associated with the build.
*
* @var GeneratorConfig
*/
private $generatorConfig;
/**
* The database.
*
* @var Database
*/
private $database;
/**
* The output writer for the SQL file.
*
* @var Writer
*/
private $sqlWriter;
/**
* The database (and output SQL file) encoding.
*
* Values will be converted to this encoding in the output file.
*
* @var string
*/
private $encoding;
/**
* The classname of the static class that will perform the building.
*
* This is needed because there are some pre/post methods that get called
* on the static class.
*
* @var string
*/
private $builderClazz;
/**
* The name of the current table being processed.
*
* @var string
*/
private $currTableName;
/**
* The DataSQLBuilder for the current table.
*
* @var DataSQLBuilder
*/
private $currBuilder;
/**
* Expat Parser.
*
* @var ExpatParser
*/
public $parser;
/**
* Flag for enabing debug output to aid in parser tracing.
*/
const DEBUG = false;
/**
* Construct new XmlToDataSQL class.
*
* This class is passed the Database object so that it knows what to expect from
* the XML file.
*
* @param Database $database
* @param GeneratorConfig $config
* @param string $encoding Database encoding
*/
public function __construct(Database $database, GeneratorConfig $config, $encoding = 'iso-8859-1')
{
$this->database = $database;
$this->generatorConfig = $config;
$this->encoding = $encoding;
}
/**
* Transform the data dump input file into SQL and writes it to the output stream.
*
* @param PhingFile $xmlFile
* @param Writer $out
*/
public function transform(PhingFile $xmlFile, Writer $out)
{
$this->sqlWriter = $out;
// Reset some vars just in case this is being run multiple times.
$this->currTableName = $this->currBuilder = null;
$this->builderClazz = $this->generatorConfig->getBuilderClassname('datasql');
try {
$fr = new FileReader($xmlFile);
} catch (Exception $e) {
throw new BuildException("XML File not found: " . $xmlFile->getAbsolutePath());
}
$br = new BufferedReader($fr);
$this->parser = new ExpatParser($br);
$this->parser->parserSetOption(XML_OPTION_CASE_FOLDING, 0);
$this->parser->setHandler($this);
try {
$this->parser->parse();
} catch (Exception $e) {
print $e->getMessage() . "\n";
$br->close();
}
$br->close();
}
/**
* Handles opening elements of the xml file.
*/
public function startElement($name, $attributes)
{
try {
if ($name == "dataset") {
// Clear any start/end DLL
call_user_func(array($this->builderClazz, 'reset'));
$this->sqlWriter->write(call_user_func(array($this->builderClazz, 'getDatabaseStartSql')));
} else {
// we're processing a row of data
// where tag name is phpName e.g. <BookReader .... />
$table = $this->database->getTableByPhpName($name);
$columnValues = array();
foreach ($attributes as $name => $value) {
$col = $table->getColumnByPhpName($name);
$columnValues[] = new ColumnValue($col, iconv('utf-8',$this->encoding, $value));
}
$data = new DataRow($table, $columnValues);
if ($this->currTableName !== $table->getName()) {
// new table encountered
if ($this->currBuilder !== null) {
$this->sqlWriter->write($this->currBuilder->getTableEndSql());
}
$this->currTableName = $table->getName();
$this->currBuilder = $this->generatorConfig->getConfiguredBuilder($table, 'datasql');
$this->sqlWriter->write($this->currBuilder->getTableStartSql());
}
// Write the SQL
$this->sqlWriter->write($this->currBuilder->buildRowSql($data));
}
} catch (Exception $e) {
// Exceptions have traditionally not bubbled up nicely from the expat parser,
// so we also print the stack trace here.
print $e;
throw $e;
}
}
/**
* Handles closing elements of the xml file.
*
* @param $name The local name (without prefix), or the empty string if
* Namespace processing is not being performed.
*/
public function endElement($name)
{
if (self::DEBUG) {
print("endElement(" . $name . ") called\n");
}
if ($name == "dataset") {
if ($this->currBuilder !== null) {
$this->sqlWriter->write($this->currBuilder->getTableEndSql());
}
$this->sqlWriter->write(call_user_func(array($this->builderClazz, 'getDatabaseEndSql')));
}
}
} // XmlToData
/**
* "inner class"
* @package propel.generator.builder.util
*/
class DataRow
{
private $table;
private $columnValues;
public function __construct(Table $table, $columnValues)
{
$this->table = $table;
$this->columnValues = $columnValues;
}
public function getTable()
{
return $this->table;
}
public function getColumnValues()
{
return $this->columnValues;
}
}
/**
* "inner" class
* @package propel.generator.builder.util
*/
class ColumnValue {
private $col;
private $val;
public function __construct(Column $col, $val)
{
$this->col = $col;
$this->val = $val;
}
public function getColumn()
{
return $this->col;
}
public function getValue()
{
return $this->val;
}
}

View file

@ -0,0 +1,217 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* A class that holds build properties and provide a class loading mechanism for the generator.
*
* @author Hans Lellelid <hans@xmpl.org>
* @package propel.generator.config
*/
class GeneratorConfig {
/**
* The build properties.
*
* @var array
*/
private $buildProperties = array();
/**
* Construct a new GeneratorConfig.
* @param mixed $props Array or Iterator
*/
public function __construct($props = null)
{
if ($props) $this->setBuildProperties($props);
}
/**
* Gets the build properties.
* @return array
*/
public function getBuildProperties()
{
return $this->buildProperties;
}
/**
* Parses the passed-in properties, renaming and saving eligible properties in this object.
*
* Renames the propel.xxx properties to just xxx and renames any xxx.yyy properties
* to xxxYyy as PHP doesn't like the xxx.yyy syntax.
*
* @param mixed $props Array or Iterator
*/
public function setBuildProperties($props)
{
$this->buildProperties = array();
$renamedPropelProps = array();
foreach ($props as $key => $propValue) {
if (strpos($key, "propel.") === 0) {
$newKey = substr($key, strlen("propel."));
$j = strpos($newKey, '.');
while ($j !== false) {
$newKey = substr($newKey, 0, $j) . ucfirst(substr($newKey, $j + 1));
$j = strpos($newKey, '.');
}
$this->setBuildProperty($newKey, $propValue);
}
}
}
/**
* Gets a specific propel (renamed) property from the build.
*
* @param string $name
* @return mixed
*/
public function getBuildProperty($name)
{
return isset($this->buildProperties[$name]) ? $this->buildProperties[$name] : null;
}
/**
* Sets a specific propel (renamed) property from the build.
*
* @param string $name
* @param mixed $value
*/
public function setBuildProperty($name, $value)
{
$this->buildProperties[$name] = $value;
}
/**
* Resolves and returns the class name based on the specified property value.
*
* @param string $propname The name of the property that holds the class path (dot-path notation).
* @return string The class name.
* @throws BuildException If the classname cannot be determined or class cannot be loaded.
*/
public function getClassname($propname)
{
$classpath = $this->getBuildProperty($propname);
if (empty($classpath)) {
throw new BuildException("Unable to find class path for '$propname' property.");
}
// This is a slight hack to workaround camel case inconsistencies for the DDL classes.
// Basically, we want to turn ?.?.?.sqliteDDLBuilder into ?.?.?.SqliteDDLBuilder
$lastdotpos = strrpos($classpath, '.');
if ($lastdotpos !== null) {
$classpath{$lastdotpos+1} = strtoupper($classpath{$lastdotpos+1});
} else {
$classpath = ucfirst($classpath);
}
if (empty($classpath)) {
throw new BuildException("Unable to find class path for '$propname' property.");
}
$clazz = Phing::import($classpath);
return $clazz;
}
/**
* Resolves and returns the builder class name.
*
* @param string $type
* @return string The class name.
*/
public function getBuilderClassname($type)
{
$propname = 'builder' . ucfirst(strtolower($type)) . 'Class';
return $this->getClassname($propname);
}
/**
* Creates and configures a new Platform class.
*
* @param PDO $con
* @return Platform
*/
public function getConfiguredPlatform(PDO $con = null)
{
$clazz = $this->getClassname("platformClass");
$platform = new $clazz();
if (!$platform instanceof Platform) {
throw new BuildException("Specified platform class ($clazz) does not implement Platform interface.", $this->getLocation());
}
$platform->setConnection($con);
$platform->setGeneratorConfig($this);
return $platform;
}
/**
* Creates and configures a new SchemaParser class for specified platform.
* @param PDO $con
* @return SchemaParser
*/
public function getConfiguredSchemaParser(PDO $con = null)
{
$clazz = $this->getClassname("reverseParserClass");
$parser = new $clazz();
if (!$parser instanceof SchemaParser) {
throw new BuildException("Specified platform class ($clazz) does implement SchemaParser interface.", $this->getLocation());
}
$parser->setConnection($con);
$parser->setGeneratorConfig($this);
return $parser;
}
/**
* Gets a configured data model builder class for specified table and based on type.
*
* @param Table $table
* @param string $type The type of builder ('ddl', 'sql', etc.)
* @return DataModelBuilder
*/
public function getConfiguredBuilder(Table $table, $type, $cache = true)
{
$classname = $this->getBuilderClassname($type);
$builder = new $classname($table);
$builder->setGeneratorConfig($this);
return $builder;
}
/**
* Gets a configured Pluralizer class.
*
* @return Pluralizer
*/
public function getConfiguredPluralizer()
{
$classname = $this->getBuilderClassname('pluralizer');
$pluralizer = new $classname();
return $pluralizer;
}
/**
* Gets a configured behavior class
*
* @param string $name a behavior name
* @return string a behavior class name
*/
public function getConfiguredBehavior($name)
{
$propname = 'behavior' . ucfirst(strtolower($name)) . 'Class';
try {
$ret = $this->getClassname($propname);
} catch (BuildException $e) {
// class path not configured
$ret = false;
}
return $ret;
}
}

View file

@ -0,0 +1,22 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'phing/BuildException.php';
/**
* The base class of all exceptions thrown by the engine.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Daniel Rall <dlr@collab.net> (Torque)
* @author Jason van Zyl <jvz@apache.org> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.exception
*/
class EngineException extends BuildException {}

View file

@ -0,0 +1,222 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'exception/EngineException.php';
require_once 'model/Database.php';
/**
* A class for holding application data structures.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Leon Messerschmidt <leon@opticode.co.za> (Torque)
* @author John McNally <jmcnally@collab.net> (Torque)
* @author Daniel Rall <dlr@finemaltcoding.com> (Torque)
* @version $Revision: 1640 $
* @package propel.generator.model
*/
class AppData
{
/**
* The list of databases for this application.
* @var array Database[]
*/
private $dbList = array();
/**
* The platform class for our database(s).
* @var string
*/
private $platform;
/**
* Name of the database. Only one database definition
* is allowed in one XML descriptor.
*/
private $name;
/**
* Flag to ensure that initialization is performed only once.
* @var boolean
*/
private $isInitialized = false;
/**
* Creates a new instance for the specified database type.
*
* @param Platform $platform The platform object to use for any databases added to this application model.
*/
public function __construct(Platform $platform)
{
$this->platform = $platform;
}
/**
* Gets the platform object to use for any databases added to this application model.
*
* @return Platform
*/
public function getPlatform()
{
return $this->platform;
}
/**
* Set the name of the database.
*
* @param name of the database.
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get the name of the database.
*
* @return String name
*/
public function getName()
{
return $this->name;
}
/**
* Get the short name of the database (without the '-schema' postfix).
*
* @return String name
*/
public function getShortName()
{
return str_replace("-schema", "", $this->name);
}
/**
* Return an array of all databases
*
* @return Array of Database objects
*/
public function getDatabases($doFinalInit = true)
{
// this is temporary until we'll have a clean solution
// for packaging datamodels/requiring schemas
if ($doFinalInit) {
$this->doFinalInitialization();
}
return $this->dbList;
}
/**
* Returns whether this application has multiple databases.
*
* @return boolean True if the application has multiple databases
*/
public function hasMultipleDatabases()
{
return (count($this->dbList) > 1);
}
/**
* Return the database with the specified name.
*
* @param name database name
* @return A Database object. If it does not exist it returns null
*/
public function getDatabase($name = null, $doFinalInit = true)
{
// this is temporary until we'll have a clean solution
// for packaging datamodels/requiring schemas
if ($doFinalInit) {
$this->doFinalInitialization();
}
if ($name === null) {
return $this->dbList[0];
}
for ($i=0,$size=count($this->dbList); $i < $size; $i++) {
$db = $this->dbList[$i];
if ($db->getName() === $name) {
return $db;
}
}
return null;
}
/**
* Checks whether a database with the specified nam exists in this AppData
*
* @param name database name
* @return boolean
*/
public function hasDatabase($name)
{
foreach ($this->dbList as $db) {
if ($db->getName() === $name) {
return true;
}
}
return false;
}
/**
* Add a database to the list and sets the AppData property to this
* AppData
*
* @param db the database to add
*/
public function addDatabase($db)
{
if ($db instanceof Database) {
$db->setAppData($this);
if ($db->getPlatform() === null) {
$db->setPlatform($this->platform);
}
$this->dbList[] = $db;
return $db;
} else {
// XML attributes array / hash
$d = new Database();
$d->setAppData($this);
if ($d->getPlatform() === null) {
$d->setPlatform($this->platform);
}
$d->loadFromXML($db);
return $this->addDatabase($d); // calls self w/ different param type
}
}
public function doFinalInitialization()
{
if (!$this->isInitialized) {
for ($i=0, $size=count($this->dbList); $i < $size; $i++) {
$this->dbList[$i]->doFinalInitialization();
}
$this->isInitialized = true;
}
}
/**
* Creats a string representation of this AppData.
* The representation is given in xml format.
*
* @return string Representation in xml format
*/
public function toString()
{
$result = "<app-data>\n";
for ($i=0,$size=count($this->dbList); $i < $size; $i++) {
$result .= $this->dbList[$i]->toString();
}
$result .= "</app-data>";
return $result;
}
}

View file

@ -0,0 +1,247 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/Index.php';
require_once 'builder/util/PropelTemplate.php';
/**
* Information about behaviors of a table.
*
* @author François Zaninotto
* @version $Revision: 1784 $
* @package propel.generator.model
*/
class Behavior extends XMLElement
{
protected $table;
protected $database;
protected $name;
protected $parameters = array();
protected $isTableModified = false;
protected $isEarly = false;
protected $dirname;
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function setTable(Table $table)
{
$this->table = $table;
}
public function getTable()
{
return $this->table;
}
public function setDatabase(Database $database)
{
$this->database = $database;
}
public function getDatabase()
{
return $this->database;
}
/**
* Add a parameter
* Expects an associative array looking like array('name' => 'foo', 'value' => bar)
*
* @param array associative array with name and value keys
*/
public function addParameter($attribute)
{
$attribute = array_change_key_case($attribute, CASE_LOWER);
$this->parameters[$attribute['name']] = $attribute['value'];
}
/**
* Overrides the behavior parameters
* Expects an associative array looking like array('foo' => 'bar')
*
* @param array associative array
*/
public function setParameters($parameters)
{
$this->parameters = $parameters;
}
/**
* Get the associative array of parameters
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
public function getParameter($name)
{
return $this->parameters[$name];
}
/**
* This method is automatically called on database behaviors when the database model is finished
* Propagate the behavior to the tables of the database
* Override this method to have a database behavior do something special
*/
public function modifyDatabase()
{
foreach ($this->getDatabase()->getTables() as $table)
{
$b = clone $this;
$table->addBehavior($b);
}
}
/**
* This method is automatically called on table behaviors when the database model is finished
* Override it to add columns to the current table
*/
public function modifyTable()
{
}
public function setTableModified($bool)
{
$this->isTableModified = $bool;
}
public function isTableModified()
{
return $this->isTableModified;
}
public function setEarly($bool = true)
{
$this->isEarly = $bool;
}
public function isEarly()
{
return $this->isEarly;
}
/**
* Use Propel's simple templating system to render a PHP file
* using variables passed as arguments.
*
* @param string $filename The template file name, relative to the behavior's dirname
* @param array $vars An associative array of argumens to be rendered
* @param string $templateDir The name of the template subdirectory
*
* @return string The rendered template
*/
public function renderTemplate($filename, $vars = array(), $templateDir = '/templates/')
{
$filePath = $this->getDirname() . $templateDir . $filename;
if (!file_exists($filePath)) {
// try with '.php' at the end
$filePath = $filePath . '.php';
if (!file_exists($filePath)) {
throw new InvalidArgumentException(sprintf('Template "%s" not found in "%s" directory',
$filename,
$this->getDirname() . $templateDir
));
}
}
$template = new PropelTemplate();
$template->setTemplateFile($filePath);
$vars = array_merge($vars, array('behavior' => $this));
return $template->render($vars);
}
/**
* Returns the current dirname of this behavior (also works for descendants)
*
* @return string The absolute directory name
*/
protected function getDirname()
{
if (null === $this->dirname) {
$r = new ReflectionObject($this);
$this->dirname = dirname($r->getFileName());
}
return $this->dirname;
}
/**
* Retrieve a column object using a name stored in the behavior parameters
* Useful for table behaviors
*
* @param string $param Name of the parameter storing the column name
* @return ColumnMap The column of the table supporting the behavior
*/
public function getColumnForParameter($param)
{
return $this->getTable()->getColumn($this->getParameter($param));
}
/**
* Sets up the Behavior object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->name = $this->getAttribute("name");
}
/**
* @see parent::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$bNode = $node->appendChild($doc->createElement('behavior'));
$bNode->setAttribute('name', $this->getName());
foreach ($this->parameters as $name => $value) {
$parameterNode = $bNode->appendChild($doc->createElement('parameter'));
$parameterNode->setAttribute('name', $name);
$parameterNode->setAttribute('value', $value);
}
}
public function getTableModifier()
{
return $this;
}
public function getObjectBuilderModifier()
{
return $this;
}
public function getQueryBuilderModifier()
{
return $this;
}
public function getPeerBuilderModifier()
{
return $this;
}
public function getTableMapBuilderModifier()
{
return $this;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,91 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* A class for holding a column default value.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class ColumnDefaultValue
{
const TYPE_VALUE = "value";
const TYPE_EXPR = "expr";
/**
* @var string The default value, as specified in the schema.
*/
private $value;
/**
* @var string The type of value represented by this object (DefaultValue::TYPE_VALUE or DefaultValue::TYPE_EXPR).
*/
private $type = ColumnDefaultValue::TYPE_VALUE;
/**
* Creates a new DefaultValue object.
*
* @param string $value The default value, as specified in the schema.
* @param string $type The type of default value (DefaultValue::TYPE_VALUE or DefaultValue::TYPE_EXPR)
*/
public function __construct($value, $type = null)
{
$this->setValue($value);
if ($type !== null) {
$this->setType($type);
}
}
/**
* @return string The type of default value (DefaultValue::TYPE_VALUE or DefaultValue::TYPE_EXPR)
*/
public function getType()
{
return $this->type;
}
/**
* @param string $type The type of default value (DefaultValue::TYPE_VALUE or DefaultValue::TYPE_EXPR)
*/
public function setType($type)
{
$this->type = $type;
}
/**
* Convenience method to indicate whether the value in this object is an expression (as opposed to simple value).
*
* @return boolean Whether value this object holds is an expression.
*/
public function isExpression()
{
return ($this->type == self::TYPE_EXPR);
}
/**
* @return string The value, as specified in the schema.
*/
public function getValue()
{
return $this->value;
}
/**
* @param string $value The value, as specified in the schema.
*/
public function setValue($value)
{
$this->value = $value;
}
}

View file

@ -0,0 +1,72 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* A <code>NameGenerator</code> implementation for table-specific
* constraints. Conforms to the maximum column name length for the
* type of database in use.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Daniel Rall <dlr@finemaltcoding.com> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class ConstraintNameGenerator implements NameGenerator
{
/**
* Conditional compilation flag.
*/
const DEBUG = false;
/**
* First element of <code>inputs</code> should be of type {@link Database}, second
* should be a table name, third is the type identifier (spared if
* trimming is necessary due to database type length constraints),
* and the fourth is a <code>Integer</code> indicating the number
* of this contraint.
*
* @see NameGenerator
* @throws EngineException
*/
public function generateName($inputs)
{
$db = $inputs[0];
$name = $inputs[1];
$namePostfix = $inputs[2];
$constraintNbr = (string) $inputs[3];
// Calculate maximum RDBMS-specific column character limit.
$maxBodyLength = -1;
try {
$maxColumnNameLength = (int) $db->getPlatform()->getMaxColumnNameLength();
$maxBodyLength = ($maxColumnNameLength - strlen($namePostfix)
- strlen($constraintNbr) - 2);
if (self::DEBUG) {
print("maxColumnNameLength=" . $maxColumnNameLength
. " maxBodyLength=" . $maxBodyLength . "\n");
}
} catch (EngineException $e) {
echo $e;
throw $e;
}
// Do any necessary trimming.
if ($maxBodyLength !== -1 && strlen($name) > $maxBodyLength) {
$name = substr($name, 0, $maxBodyLength);
}
$name .= self::STD_SEPARATOR_CHAR . $namePostfix
. self::STD_SEPARATOR_CHAR . $constraintNbr;
return $name;
}
}

View file

@ -0,0 +1,676 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
require_once 'model/IDMethod.php';
require_once 'model/NameGenerator.php';
require_once 'model/Table.php';
require_once 'model/Behavior.php';
/**
* A class for holding application data structures.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Leon Messerschmidt <leon@opticode.co.za> (Torque)
* @author John McNally<jmcnally@collab.net> (Torque)
* @author Martin Poeschl<mpoeschl@marmot.at> (Torque)
* @author Daniel Rall<dlr@collab.net> (Torque)
* @author Byron Foster <byron_foster@yahoo.com> (Torque)
* @version $Revision: 1802 $
* @package propel.generator.model
*/
class Database extends XMLElement
{
private $platform;
private $tableList = array();
private $curColumn;
private $name;
private $pkg;
/**
* Namespace for the generated OM.
*
* @var string
*/
protected $namespace;
private $baseClass;
private $basePeer;
private $defaultIdMethod;
private $defaultPhpNamingMethod;
private $defaultTranslateMethod;
private $dbParent;
private $tablesByName = array();
private $tablesByPhpName = array();
private $heavyIndexing;
protected $tablePrefix = '';
private $domainMap = array();
/**
* List of behaviors registered for this table
*
* @var array
*/
protected $behaviors = array();
/**
* Constructs a new Database object.
*
* @param string $name
*/
public function __construct($name = null)
{
$this->name = $name;
}
/**
* Sets up the Database object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->name = $this->getAttribute("name");
$namespace = $this->getAttribute("namespace", '');
$package = $this->getAttribute("package");
if ($namespace && !$package && $this->getBuildProperty('namespaceAutoPackage')) {
$package = str_replace('\\', '.', $namespace);
}
$this->namespace = $namespace;
$this->pkg = $package;
$this->baseClass = $this->getAttribute("baseClass");
$this->basePeer = $this->getAttribute("basePeer");
$this->defaultIdMethod = $this->getAttribute("defaultIdMethod", IDMethod::NATIVE);
$this->defaultPhpNamingMethod = $this->getAttribute("defaultPhpNamingMethod", NameGenerator::CONV_METHOD_UNDERSCORE);
$this->defaultTranslateMethod = $this->getAttribute("defaultTranslateMethod", Validator::TRANSLATE_NONE);
$this->heavyIndexing = $this->booleanValue($this->getAttribute("heavyIndexing"));
$this->tablePrefix = $this->getAttribute('tablePrefix', $this->getBuildProperty('tablePrefix'));
}
/**
* Returns the Platform implementation for this database.
*
* @return Platform a Platform implementation
*/
public function getPlatform()
{
return $this->platform;
}
/**
* Sets the Platform implementation for this database.
*
* @param Platform $platform A Platform implementation
*/
public function setPlatform($platform)
{
$this->platform = $platform;
}
/**
* Get the name of the Database
*/
public function getName()
{
return $this->name;
}
/**
* Set the name of the Database
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get the value of package.
* @return value of package.
*/
public function getPackage()
{
return $this->pkg;
}
/**
* Set the value of package.
* @param v Value to assign to package.
*/
public function setPackage($v)
{
$this->pkg = $v;
}
/**
* Get the value of the namespace.
* @return value of namespace.
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* Set the value of the namespace.
* @param v Value to assign to namespace.
*/
public function setNamespace($v)
{
$this->namespace = $v;
}
/**
* Get the value of baseClass.
* @return value of baseClass.
*/
public function getBaseClass()
{
return $this->baseClass;
}
/**
* Set the value of baseClass.
* @param v Value to assign to baseClass.
*/
public function setBaseClass($v)
{
$this->baseClass = $v;
}
/**
* Get the value of basePeer.
* @return value of basePeer.
*/
public function getBasePeer()
{
return $this->basePeer;
}
/**
* Set the value of basePeer.
* @param v Value to assign to basePeer.
*/
public function setBasePeer($v)
{
$this->basePeer = $v;
}
/**
* Get the value of defaultIdMethod.
* @return value of defaultIdMethod.
*/
public function getDefaultIdMethod()
{
return $this->defaultIdMethod;
}
/**
* Set the value of defaultIdMethod.
* @param v Value to assign to defaultIdMethod.
*/
public function setDefaultIdMethod($v)
{
$this->defaultIdMethod = $v;
}
/**
* Get the value of defaultPHPNamingMethod which specifies the
* method for converting schema names for table and column to PHP names.
* @return string The default naming conversion used by this database.
*/
public function getDefaultPhpNamingMethod()
{
return $this->defaultPhpNamingMethod;
}
/**
* Set the value of defaultPHPNamingMethod.
* @param string $v The default naming conversion for this database to use.
*/
public function setDefaultPhpNamingMethod($v)
{
$this->defaultPhpNamingMethod = $v;
}
/**
* Get the value of defaultTranslateMethod which specifies the
* method for translate validator error messages.
* @return string The default translate method.
*/
public function getDefaultTranslateMethod()
{
return $this->defaultTranslateMethod;
}
/**
* Set the value of defaultTranslateMethod.
* @param string $v The default translate method to use.
*/
public function setDefaultTranslateMethod($v)
{
$this->defaultTranslateMethod = $v;
}
/**
* Get the value of heavyIndexing.
*
* This is a synonym for getHeavyIndexing().
*
* @return boolean Value of heavyIndexing.
* @see getHeavyIndexing()
*/
public function isHeavyIndexing()
{
return $this->getHeavyIndexing();
}
/**
* Get the value of heavyIndexing.
*
* @return boolean Value of heavyIndexing.
*/
public function getHeavyIndexing()
{
return $this->heavyIndexing;
}
/**
* Set the value of heavyIndexing.
* @param boolean $v Value to assign to heavyIndexing.
*/
public function setHeavyIndexing($v)
{
$this->heavyIndexing = (boolean) $v;
}
/**
* Return an array of all tables
*/
public function getTables()
{
return $this->tableList;
}
/**
* Check whether the database has a table.
* @return boolean
*/
public function hasTable($name)
{
return array_key_exists($name, $this->tablesByName);
}
/**
* Return the table with the specified name.
* @param string $name The name of the table (e.g. 'my_table')
* @return Table a Table object or null if it doesn't exist
*/
public function getTable($name)
{
if ($this->hasTable($name)) {
return $this->tablesByName[$name];
}
return null; // just to be explicit
}
/**
* Return the table with the specified phpName.
* @param string $phpName the PHP Name of the table (e.g. 'MyTable')
* @return Table a Table object or null if it doesn't exist
*/
public function getTableByPhpName($phpName)
{
if (isset($this->tablesByPhpName[$phpName])) {
return $this->tablesByPhpName[$phpName];
}
return null; // just to be explicit
}
/**
* An utility method to add a new table from an xml attribute.
*/
public function addTable($data)
{
if ($data instanceof Table) {
$tbl = $data; // alias
$tbl->setDatabase($this);
if (isset($this->tablesByName[$tbl->getName()])) {
throw new EngineException("Duplicate table declared: " . $tbl->getName());
}
$this->tableList[] = $tbl;
$this->tablesByName[ $tbl->getName() ] = $tbl;
$this->tablesByPhpName[ $tbl->getPhpName() ] = $tbl;
if ($tbl->getPackage() === null) {
$tbl->setPackage($this->getPackage());
}
return $tbl;
} else {
$tbl = new Table();
$tbl->setDatabase($this);
$tbl->loadFromXML($data);
return $this->addTable($tbl); // call self w/ different param
}
}
/**
* Set the parent of the database
*/
public function setAppData(AppData $parent)
{
$this->dbParent = $parent;
}
/**
* Get the parent of the table
*/
public function getAppData()
{
return $this->dbParent;
}
/**
* Adds Domain object from <domain> tag.
* @param mixed XML attributes (array) or Domain object.
*/
public function addDomain($data) {
if ($data instanceof Domain) {
$domain = $data; // alias
$domain->setDatabase($this);
$this->domainMap[ $domain->getName() ] = $domain;
return $domain;
} else {
$domain = new Domain();
$domain->setDatabase($this);
$domain->loadFromXML($data);
return $this->addDomain($domain); // call self w/ different param
}
}
/**
* Get already configured Domain object by name.
* @return Domain
*/
public function getDomain($domainName)
{
if (isset($this->domainMap[$domainName])) {
return $this->domainMap[$domainName];
}
return null; // just to be explicit
}
public function getGeneratorConfig()
{
if ($this->getAppData() && $this->getAppData()->getPlatform()) {
return $this->getAppData()->getPlatform()->getGeneratorConfig();
} else {
return null;
}
}
public function getBuildProperty($key)
{
if($config = $this->getGeneratorConfig()) {
return $config->getBuildProperty($key);
} else {
return '';
}
}
/**
* Adds a new Behavior to the database
* @return Behavior A behavior instance
*/
public function addBehavior($bdata)
{
if ($bdata instanceof Behavior) {
$behavior = $bdata;
$behavior->setDatabase($this);
$this->behaviors[$behavior->getName()] = $behavior;
return $behavior;
} else {
$class = $this->getConfiguredBehavior($bdata['name']);
$behavior = new $class();
$behavior->loadFromXML($bdata);
return $this->addBehavior($behavior);
}
}
/**
* Get the database behaviors
* @return Array of Behavior objects
*/
public function getBehaviors()
{
return $this->behaviors;
}
/**
* check if the database has a behavior by name
*
* @param string $name the behavior name
* @return boolean True if the behavior exists
*/
public function hasBehavior($name)
{
return array_key_exists($name, $this->behaviors);
}
/**
* Get one database behavior by name
* @param string $name the behavior name
* @return Behavior a behavior object
*/
public function getBehavior($name)
{
return $this->behaviors[$name];
}
/**
* Get the table prefix for this database
*
* @return string the table prefix
*/
public function getTablePrefix()
{
return $this->tablePrefix;
}
public function doFinalInitialization()
{
if($defaultBehaviors = $this->getBuildProperty('behaviorDefault')) {
// add generic behaviors from build.properties
$defaultBehaviors = explode(',', $defaultBehaviors);
foreach ($defaultBehaviors as $behavior) {
$this->addBehavior(array('name' => trim($behavior)));
}
}
// execute behavior database modifiers
foreach ($this->getBehaviors() as $behavior) {
$behavior->modifyDatabase();
}
$tables = $this->getTables();
// execute early table behaviors
foreach ($tables as $table) {
foreach ($table->getEarlyBehaviors() as $behavior) {
if (!$behavior->isTableModified()) {
$behavior->getTableModifier()->modifyTable();
$behavior->setTableModified(true);
}
}
}
for ($i=0,$size=count($tables); $i < $size; $i++) {
$currTable = $tables[$i];
// check schema integrity
// if idMethod="autoincrement", make sure a column is
// specified as autoIncrement="true"
// FIXME: Handle idMethod="native" via DB adapter.
/*
--- REMOVING THIS BECAUSE IT'S ANNOYING
if ($currTable->getIdMethod() == IDMethod::NATIVE ) {
$columns = $currTable->getColumns();
$foundOne = false;
for ($j=0, $cLen=count($columns); $j < $cLen && !$foundOne; $j++) {
$foundOne = $columns[$j]->isAutoIncrement();
}
if (!$foundOne) {
$errorMessage = "Table '" . $currTable->getName()
. "' is set to use native id generation, but it does not "
. "have a column which declared as the one to "
. "auto increment (i.e. autoIncrement=\"true\")";
throw new BuildException($errorMessage);
}
}
*/
$currTable->doFinalInitialization();
// setup reverse fk relations
$fks = $currTable->getForeignKeys();
for ($j=0, $fksLen=count($fks); $j < $fksLen; $j++) {
$currFK = $fks[$j];
$foreignTable = $this->getTable($currFK->getForeignTableName());
if ($foreignTable === null) {
throw new BuildException("ERROR!! Attempt to set foreign"
. " key to nonexistent table, "
. $currFK->getForeignTableName() . "!");
}
$referrers = $foreignTable->getReferrers();
if ($referrers === null || !in_array($currFK, $referrers, true) ) {
$foreignTable->addReferrer($currFK);
}
// local column references
$localColumnNames = $currFK->getLocalColumns();
for ($k=0,$lcnLen=count($localColumnNames); $k < $lcnLen; $k++) {
$local = $currTable->getColumn($localColumnNames[$k]);
// give notice of a schema inconsistency.
// note we do not prevent the npe as there is nothing
// that we can do, if it is to occur.
if ($local === null) {
throw new BuildException("ERROR!! Attempt to define foreign"
. " key with nonexistent column, "
. $localColumnNames[$k] . ", in table, "
. $currTable->getName() . "!");
}
//check for foreign pk's
if ($local->isPrimaryKey()) {
$currTable->setContainsForeignPK(true);
}
} // for each local col name
// foreign column references
$foreignColumnNames = $currFK->getForeignColumns();
for ($k=0,$fcnLen=count($localColumnNames); $k < $fcnLen; $k++) {
$foreign = $foreignTable->getColumn($foreignColumnNames[$k]);
// if the foreign column does not exist, we may have an
// external reference or a misspelling
if ($foreign === null) {
throw new BuildException("ERROR!! Attempt to set foreign"
. " key to nonexistent column, "
. $foreignColumnNames[$k] . ", in table, "
. $foreignTable->getName() . "!");
} else {
$foreign->addReferrer($currFK);
}
} // for each foreign col ref
}
}
// Behaviors may have added behaviors of their own
// These behaviors must launch their modifyTable() method,
// Until there is no behavior left
$behaviorsLeft = true;
while ($behaviorsLeft) {
$behaviorsLeft = false;
foreach ($tables as $table) {
foreach ($table->getBehaviors() as $behavior) {
if (!$behavior->isTableModified()) {
$behavior->getTableModifier()->modifyTable();
$behavior->setTableModified(true);
$behaviorsLeft = true;
}
}
}
}
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$dbNode = $node->appendChild($doc->createElement('database'));
$dbNode->setAttribute('name', $this->name);
if ($this->pkg) {
$dbNode->setAttribute('package', $this->pkg);
}
if ($this->defaultIdMethod) {
$dbNode->setAttribute('defaultIdMethod', $this->defaultIdMethod);
}
if ($this->baseClass) {
$dbNode->setAttribute('baseClass', $this->baseClass);
}
if ($this->basePeer) {
$dbNode->setAttribute('basePeer', $this->basePeer);
}
if ($this->defaultPhpNamingMethod) {
$dbNode->setAttribute('defaultPhpNamingMethod', $this->defaultPhpNamingMethod);
}
if ($this->defaultTranslateMethod) {
$dbNode->setAttribute('defaultTranslateMethod', $this->defaultTranslateMethod);
}
/*
FIXME - Before we can add support for domains in the schema, we need
to have a method of the Column that indicates whether the column was mapped
to a SPECIFIC domain (since Column->getDomain() will always return a Domain object)
foreach ($this->domainMap as $domain) {
$domain->appendXml($dbNode);
}
*/
foreach ($this->vendorInfos as $vi) {
$vi->appendXml($dbNode);
}
foreach ($this->tableList as $table) {
$table->appendXml($dbNode);
}
}
}

View file

@ -0,0 +1,386 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
/**
* A class for holding data about a domain used in the schema.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class Domain extends XMLElement
{
/**
* @var string The name of this domain
*/
private $name;
/**
* @var string Description for this domain.
*/
private $description;
/**
* @var int Size
*/
private $size;
/**
* @var int Scale
*/
private $scale;
/**
* @var int Propel type from schema
*/
private $propelType;
/**
* @var string The SQL type to use for this column
*/
private $sqlType;
/**
* @var ColumnDefaultValue A default value
*/
private $defaultValue;
/**
* @var Database
*/
private $database;
/**
* Creates a new Domain object.
* If this domain needs a name, it must be specified manually.
*
* @param string $type Propel type.
* @param string $sqlType SQL type.
* @param string $size
* @param string $scale
*/
public function __construct($type = null, $sqlType = null, $size = null, $scale = null)
{
$this->propelType = $type;
$this->sqlType = ($sqlType !== null) ? $sqlType : $type;
$this->size = $size;
$this->scale = $scale;
}
/**
* Copy the values from current object into passed-in Domain.
* @param Domain $domain Domain to copy values into.
*/
public function copy(Domain $domain)
{
$this->defaultValue = $domain->getDefaultValue();
$this->description = $domain->getDescription();
$this->name = $domain->getName();
$this->scale = $domain->getScale();
$this->size = $domain->getSize();
$this->sqlType = $domain->getSqlType();
$this->propelType = $domain->getType();
}
/**
* Sets up the Domain object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$schemaType = strtoupper($this->getAttribute("type"));
$this->copy($this->getDatabase()->getPlatform()->getDomainForType($schemaType));
//Name
$this->name = $this->getAttribute("name");
// Default value
$defval = $this->getAttribute("defaultValue", $this->getAttribute("default"));
if ($defval !== null) {
$this->setDefaultValue(new ColumnDefaultValue($defval, ColumnDefaultValue::TYPE_VALUE));
} elseif ($this->getAttribute("defaultExpr") !== null) {
$this->setDefaultValue(new ColumnDefaultValue($this->getAttribute("defaultExpr"), ColumnDefaultValue::TYPE_EXPR));
}
$this->size = $this->getAttribute("size");
$this->scale = $this->getAttribute("scale");
$this->description = $this->getAttribute("description");
}
/**
* Sets the owning database object (if this domain is being setup via XML).
* @param Database $database
*/
public function setDatabase(Database $database)
{
$this->database = $database;
}
/**
* Gets the owning database object (if this domain was setup via XML).
* @return Database
*/
public function getDatabase()
{
return $this->database;
}
/**
* @return string Returns the description.
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description The description to set.
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @return string Returns the name.
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name The name to set.
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string Returns the scale.
*/
public function getScale()
{
return $this->scale;
}
/**
* @param string $scale The scale to set.
*/
public function setScale($scale)
{
$this->scale = $scale;
}
/**
* Replaces the size if the new value is not null.
*
* @param string $value The size to set.
*/
public function replaceScale($value)
{
if ($value !== null) {
$this->scale = $value;
}
}
/**
* @return int Returns the size.
*/
public function getSize()
{
return $this->size;
}
/**
* @param int $size The size to set.
*/
public function setSize($size)
{
$this->size = $size;
}
/**
* Replaces the size if the new value is not null.
*
* @param int $value The size to set.
*/
public function replaceSize($value)
{
if ($value !== null) {
$this->size = $value;
}
}
/**
* @return string Returns the propelType.
*/
public function getType()
{
return $this->propelType;
}
/**
* @param string $propelType The PropelTypes type to set.
*/
public function setType($propelType)
{
$this->propelType = $propelType;
}
/**
* Replaces the type if the new value is not null.
*
* @param string $value The tyep to set.
*/
public function replaceType($value)
{
if ($value !== null) {
$this->propelType = $value;
}
}
/**
* Gets the default value object.
* @return ColumnDefaultValue The default value object for this domain.
*/
public function getDefaultValue()
{
return $this->defaultValue;
}
/**
* Gets the default value, type-casted for use in PHP OM.
* @return mixed
* @see getDefaultValue()
*/
public function getPhpDefaultValue()
{
if ($this->defaultValue === null) {
return null;
} else {
if ($this->defaultValue->isExpression()) {
throw new EngineException("Cannot get PHP version of default value for default value EXPRESSION.");
}
if ($this->propelType === PropelTypes::BOOLEAN || $this->propelType === PropelTypes::BOOLEAN_EMU) {
return $this->booleanValue($this->defaultValue->getValue());
} else {
return $this->defaultValue->getValue();
}
}
}
/**
* @param ColumnDefaultValue $value The column default value to set.
*/
public function setDefaultValue(ColumnDefaultValue $value)
{
$this->defaultValue = $value;
}
/**
* Replaces the default value if the new value is not null.
*
* @param ColumnDefaultValue $value The defualt value object
*/
public function replaceDefaultValue(ColumnDefaultValue $value = null)
{
if ($value !== null) {
$this->defaultValue = $value;
}
}
/**
* @return string Returns the sqlType.
*/
public function getSqlType()
{
return $this->sqlType;
}
/**
* @param string $sqlType The sqlType to set.
*/
public function setSqlType($sqlType)
{
$this->sqlType = $sqlType;
}
/**
* Replaces the SQL type if the new value is not null.
* @param string $sqlType The native SQL type to use for this domain.
*/
public function replaceSqlType($sqlType)
{
if ($sqlType !== null) {
$this->sqlType = $sqlType;
}
}
/**
* Return the size and scale in brackets for use in an sql schema.
*
* @return string Size and scale or an empty String if there are no values
* available.
*/
public function printSize()
{
if ($this->size !== null && $this->scale !== null) {
return '(' . $this->size . ',' . $this->scale . ')';
} elseif ($this->size !== null) {
return '(' . $this->size . ')';
} else {
return "";
}
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$domainNode = $node->appendChild($doc->createElement('domain'));
$domainNode->setAttribute('type', $this->getType());
$domainNode->setAttribute('name', $this->getName());
if ($this->sqlType !== $this->getType()) {
$domainNode->setAttribute('sqlType', $this->sqlType);
}
$def = $this->getDefaultValue();
if ($def) {
if ($def->isExpression()) {
$domainNode->setAttribute('defaultExpr', $def->getValue());
} else {
$domainNode->setAttribute('defaultValue', $def->getValue());
}
}
if ($this->size) {
$domainNode->setAttribute('size', $this->size);
}
if ($this->scale) {
$domainNode->setAttribute('scale', $this->scale);
}
if ($this->description) {
$domainNode->setAttribute('description', $this->description);
}
}
}

View file

@ -0,0 +1,509 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
/**
* A Class for information about foreign keys of a table.
*
* @author Hans Lellelid <hans@xmpl.org>
* @author Fedor <fedor.karpelevitch@home.com>
* @author Daniel Rall <dlr@finemaltcoding.com>
* @version $Revision: 1778 $
* @package propel.generator.model
*/
class ForeignKey extends XMLElement
{
protected $foreignTableName;
protected $name;
protected $phpName;
protected $refPhpName;
protected $defaultJoin;
protected $onUpdate;
protected $onDelete;
protected $parentTable;
protected $localColumns = array();
protected $foreignColumns = array();
// the uppercase equivalent of the onDelete/onUpdate values in the dtd
const NONE = ""; // No "ON [ DELETE | UPDATE]" behaviour specified.
const NOACTION = "NO ACTION";
const CASCADE = "CASCADE";
const RESTRICT = "RESTRICT";
const SETDEFAULT = "SET DEFAULT";
const SETNULL = "SET NULL";
/**
* Constructs a new ForeignKey object.
*
* @param string $name
*/
public function __construct($name=null)
{
$this->name = $name;
}
/**
* Sets up the ForeignKey object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->foreignTableName = $this->getTable()->getDatabase()->getTablePrefix() . $this->getAttribute("foreignTable");
$this->name = $this->getAttribute("name");
$this->phpName = $this->getAttribute("phpName");
$this->refPhpName = $this->getAttribute("refPhpName");
$this->defaultJoin = $this->getAttribute('defaultJoin');
$this->onUpdate = $this->normalizeFKey($this->getAttribute("onUpdate"));
$this->onDelete = $this->normalizeFKey($this->getAttribute("onDelete"));
}
/**
* normalizes the input of onDelete, onUpdate attributes
*/
private function normalizeFKey($attrib)
{
if ($attrib === null || strtoupper($attrib) == "NONE") {
$attrib = self::NONE;
}
$attrib = strtoupper($attrib);
if ($attrib == "SETNULL") {
$attrib = self::SETNULL;
}
return $attrib;
}
/**
* returns whether or not the onUpdate attribute is set
*/
public function hasOnUpdate()
{
return ($this->onUpdate !== self::NONE);
}
/**
* returns whether or not the onDelete attribute is set
*/
public function hasOnDelete()
{
return ($this->onDelete !== self::NONE);
}
/**
* returns the onUpdate attribute
* @return string
*/
public function getOnUpdate()
{
return $this->onUpdate;
}
/**
* Returns the onDelete attribute
* @return string
*/
public function getOnDelete()
{
return $this->onDelete;
}
/**
* sets the onDelete attribute
*/
public function setOnDelete($value)
{
$this->onDelete = $this->normalizeFKey($value);
}
/**
* sets the onUpdate attribute
*/
public function setOnUpdate($value)
{
$this->onUpdate = $this->normalizeFKey($value);
}
/**
* Returns the name attribute.
*/
public function getName()
{
return $this->name;
}
/**
* Sets the name attribute.
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Gets the phpName for this foreign key (if any).
* @return string
*/
public function getPhpName()
{
return $this->phpName;
}
/**
* Sets a phpName to use for this foreign key.
* @param string $name
*/
public function setPhpName($name)
{
$this->phpName = $name;
}
/**
* Gets the refPhpName for this foreign key (if any).
* @return string
*/
public function getRefPhpName()
{
return $this->refPhpName;
}
/**
* Sets a refPhpName to use for this foreign key.
* @param string $name
*/
public function setRefPhpName($name)
{
$this->refPhpName = $name;
}
/**
* Gets the defaultJoin for this foreign key (if any).
* @return string
*/
public function getDefaultJoin()
{
return $this->defaultJoin;
}
/**
* Sets a defaultJoin to use for this foreign key.
* @param string $name
*/
public function setDefaultJoin($defaultJoin)
{
$this->defaultJoin = $defaultJoin;
}
/**
* Get the foreignTableName of the FK
*/
public function getForeignTableName()
{
return $this->foreignTableName;
}
/**
* Set the foreignTableName of the FK
*/
public function setForeignTableName($tableName)
{
$this->foreignTableName = $tableName;
}
/**
* Gets the resolved foreign Table model object.
* @return Table
*/
public function getForeignTable()
{
return $this->getTable()->getDatabase()->getTable($this->getForeignTableName());
}
/**
* Set the parent Table of the foreign key
*/
public function setTable(Table $parent)
{
$this->parentTable = $parent;
}
/**
* Get the parent Table of the foreign key
*/
public function getTable()
{
return $this->parentTable;
}
/**
* Returns the Name of the table the foreign key is in
*/
public function getTableName()
{
return $this->parentTable->getName();
}
/**
* Adds a new reference entry to the foreign key.
*/
public function addReference($p1, $p2 = null)
{
if (is_array($p1)) {
$this->addReference(@$p1["local"], @$p1["foreign"]);
} else {
if ($p1 instanceof Column) {
$p1 = $p1->getName();
}
if ($p2 instanceof Column) {
$p2 = $p2->getName();
}
$this->localColumns[] = $p1;
$this->foreignColumns[] = $p2;
}
}
/**
* Clear the references of this foreign key
*/
public function clearReferences()
{
$this->localColumns[] = array();
$this->foreignColumns[] = array();
}
/**
* Return a comma delimited string of local column names
* @deprecated because Column::makeList() is deprecated; use the array-returning getLocalColumns() and DDLBuilder->getColumnList() instead instead.
*/
public function getLocalColumnNames()
{
return Column::makeList($this->getLocalColumns(), $this->getTable()->getDatabase()->getPlatform());
}
/**
* Return a comma delimited string of foreign column names
* @deprecated because Column::makeList() is deprecated; use the array-returning getForeignColumns() and DDLBuilder->getColumnList() instead instead.
*/
public function getForeignColumnNames()
{
return Column::makeList($this->getForeignColumns(), $this->getTable()->getDatabase()->getPlatform());
}
/**
* Return an array of local column names.
* @return array string[]
*/
public function getLocalColumns()
{
return $this->localColumns;
}
/**
* Utility method to get local column to foreign column
* mapping for this foreign key.
*/
public function getLocalForeignMapping()
{
$h = array();
for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
$h[$this->localColumns[$i]] = $this->foreignColumns[$i];
}
return $h;
}
/**
* Utility method to get local column to foreign column
* mapping for this foreign key.
*/
public function getForeignLocalMapping()
{
$h = array();
for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
$h[$this->foreignColumns[$i]] = $this->localColumns[$i];
}
return $h;
}
/**
* Utility method to get local and foreign column objects
* mapping for this foreign key.
*/
public function getColumnObjectsMapping()
{
$mapping = array();
$localTable = $this->getTable();
$foreignTable = $this->getForeignTable();
for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
$mapping[]= array(
'local' => $localTable->getColumn($this->localColumns[$i]),
'foreign' => $foreignTable->getColumn($this->foreignColumns[$i]),
);
}
return $mapping;
}
/**
* Get the foreign column mapped to specified local column.
* @return string Column name.
*/
public function getMappedForeignColumn($local)
{
$m = $this->getLocalForeignMapping();
if (isset($m[$local])) {
return $m[$local];
}
return null;
}
/**
* Get the local column mapped to specified foreign column.
* @return string Column name.
*/
public function getMappedLocalColumn($foreign)
{
$m = $this->getForeignLocalMapping();
if (isset($m[$foreign])) {
return $m[$foreign];
}
return null;
}
/**
* Return an array of foreign column objects.
* @return array Column[]
*/
public function getForeignColumns()
{
return $this->foreignColumns;
}
/**
* Whether this foreign key uses a required column, or a list or required columns.
*
* @return boolean
*/
public function isLocalColumnsRequired()
{
foreach ($this->getLocalColumns() as $columnName) {
if (!$this->getTable()->getColumn($columnName)->isNotNull()) {
return false;
}
}
return true;
}
/**
* Whether this foreign key is also the primary key of the local table.
*
* @return boolean
*/
public function isLocalPrimaryKey()
{
$localCols = $this->getLocalColumns();
$localPKColumnObjs = $this->getTable()->getPrimaryKey();
$localPKCols = array();
foreach ($localPKColumnObjs as $lPKCol) {
$localPKCols[] = $lPKCol->getName();
}
return (!array_diff($localPKCols, $localCols));
}
/**
* Whether this foreign key is matched by an invertes foreign key (on foreign table).
*
* This is to prevent duplicate columns being generated for a 1:1 relationship that is represented
* by foreign keys on both tables. I don't know if that's good practice ... but hell, why not
* support it.
*
* @param ForeignKey $fk
* @return boolean
* @link http://propel.phpdb.org/trac/ticket/549
*/
public function isMatchedByInverseFK()
{
return (bool) $this->getInverseFK();
}
public function getInverseFK()
{
$foreignTable = $this->getForeignTable();
$map = $this->getForeignLocalMapping();
foreach ($foreignTable->getForeignKeys() as $refFK) {
$fkMap = $refFK->getLocalForeignMapping();
if ( ($refFK->getTableName() == $this->getTableName()) && ($map == $fkMap) ) { // compares keys and values, but doesn't care about order, included check to make sure it's the same table (fixes #679)
return $refFK;
}
}
}
/**
* Get the other foreign keys starting on the same table
* Used in many-to-many relationships
*
* @return ForeignKey
*/
public function getOtherFks()
{
$fks = array();
foreach ($this->getTable()->getForeignKeys() as $fk) {
if ($fk !== $this) {
$fks[]= $fk;
}
}
return $fks;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$fkNode = $node->appendChild($doc->createElement('foreign-key'));
$fkNode->setAttribute('foreignTable', $this->getForeignTableName());
$fkNode->setAttribute('name', $this->getName());
if ($this->getPhpName()) {
$fkNode->setAttribute('phpName', $this->getPhpName());
}
if ($this->getRefPhpName()) {
$fkNode->setAttribute('refPhpName', $this->getRefPhpName());
}
if ($this->getDefaultJoin()) {
$fkNode->setAttribute('defaultJoin', $this->getDefaultJoin());
}
if ($this->getOnDelete()) {
$fkNode->setAttribute('onDelete', $this->getOnDelete());
}
if ($this->getOnUpdate()) {
$fkNode->setAttribute('onUpdate', $this->getOnUpdate());
}
for ($i=0, $size=count($this->localColumns); $i < $size; $i++) {
$refNode = $fkNode->appendChild($doc->createElement('reference'));
$refNode->setAttribute('local', $this->localColumns[$i]);
$refNode->setAttribute('foreign', $this->foreignColumns[$i]);
}
foreach ($this->vendorInfos as $vi) {
$vi->appendXml($fkNode);
}
}
}

View file

@ -0,0 +1,35 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* Interface for various ID retrieval method types
* (i.e. auto-increment, sequence, ID broker, etc.).
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Daniel Rall <dlr@collab.net> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
interface IDMethod
{
/**
* Key generation via database-specific ID method
* (i.e. auto-increment for MySQL, sequence for Oracle, etc.).
*/
const NATIVE = "native";
/**
* No RDBMS key generation (keys may be generated by the
* application).
*/
const NO_ID_METHOD = "none";
}

View file

@ -0,0 +1,108 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
/**
* Information related to an ID method.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author John McNally <jmcnally@collab.net> (Torque)
* @author Daniel Rall <dlr@collab.net> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class IdMethodParameter extends XMLElement
{
private $name;
private $value;
private $parentTable;
/**
* Sets up the IdMethodParameter object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->name = $this->getAttribute("name");
$this->value = $this->getAttribute("value");
}
/**
* Get the parameter name
*/
public function getName()
{
return $this->name;
}
/**
* Set the parameter name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get the parameter value
*/
public function getValue()
{
return $this->value;
}
/**
* Set the parameter value
*/
public function setValue($value)
{
$this->value = $value;
}
/**
* Set the parent Table of the id method
*/
public function setTable(Table $parent)
{
$this->parentTable = $parent;
}
/**
* Get the parent Table of the id method
*/
public function getTable()
{
return $this->parentTable;
}
/**
* Returns the Name of the table the id method is in
*/
public function getTableName()
{
return $this->parentTable->getName();
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$paramNode = $node->appendChild($doc->createElement('id-method-parameter'));
if ($this->getName()) {
$paramNode->setAttribute('name', $this->getName());
}
$paramNode->setAttribute('value', $this->getValue());
}
}

View file

@ -0,0 +1,285 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
require_once 'exception/EngineException.php';
/**
* Information about indices of a table.
*
* @author Jason van Zyl <vanzyl@apache.org>
* @author Daniel Rall <dlr@finemaltcoding.com>
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class Index extends XMLElement
{
/** enables debug output */
const DEBUG = false;
private $indexName;
private $parentTable;
/** @var array string[] */
private $indexColumns;
/** @var array */
private $indexColumnSizes = array();
/**
* Creates a new Index instance.
*
* @param string $name
*/
public function __construct($name=null)
{
$this->indexName = $name;
}
private function createName()
{
$table = $this->getTable();
$inputs = array();
$inputs[] = $table->getDatabase();
$inputs[] = $table->getName();
if ($this->isUnique()) {
$inputs[] = "U";
} else {
$inputs[] = "I";
}
// ASSUMPTION: This Index not yet added to the list.
if ($this->isUnique()) {
$inputs[] = count($table->getUnices()) + 1;
} else {
$inputs[] = count($table->getIndices()) + 1;
}
$this->indexName = NameFactory::generateName(
NameFactory::CONSTRAINT_GENERATOR, $inputs);
}
/**
* Sets up the Index object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->indexName = $this->getAttribute("name");
}
/**
* @see #isUnique()
* @deprecated Use isUnique() instead.
*/
public function getIsUnique()
{
return $this->isUnique();
}
/**
* Returns the uniqueness of this index.
*/
public function isUnique()
{
return false;
}
/**
* @see #getName()
* @deprecated Use getName() instead.
*/
public function getIndexName()
{
return $this->getName();
}
/**
* Gets the name of this index.
*/
public function getName()
{
if ($this->indexName === null) {
try {
// generate an index name if we don't have a supplied one
$this->createName();
} catch (EngineException $e) {
// still no name
}
}
return substr($this->indexName, 0, $this->getTable()->getDatabase()->getPlatform()->getMaxColumnNameLength());
}
/**
* @see #setName(String name)
* @deprecated Use setName(String name) instead.
*/
public function setIndexName($name)
{
$this->setName($name);
}
/**
* Set the name of this index.
*/
public function setName($name)
{
$this->indexName = $name;
}
/**
* Set the parent Table of the index
*/
public function setTable(Table $parent)
{
$this->parentTable = $parent;
}
/**
* Get the parent Table of the index
*/
public function getTable()
{
return $this->parentTable;
}
/**
* Returns the Name of the table the index is in
*/
public function getTableName()
{
return $this->parentTable->getName();
}
/**
* Adds a new column to an index.
* @param mixed $data Column or attributes from XML.
*/
public function addColumn($data)
{
if ($data instanceof Column) {
$column = $data;
$this->indexColumns[] = $column->getName();
if ($column->getSize()) {
$this->indexColumnSizes[$column->getName()] = $column->getSize();
}
} else {
$attrib = $data;
$name = $attrib["name"];
$this->indexColumns[] = $name;
if (isset($attrib["size"])) {
$this->indexColumnSizes[$name] = $attrib["size"];
}
}
}
/**
* Sets array of columns to use for index.
*
* @param array $indexColumns Column[]
*/
public function setColumns(array $indexColumns)
{
$this->indexColumns = array();
$this->indexColumnSizes = array();
foreach ($indexColumns as $col) {
$this->addColumn($col);
}
}
/**
* Whether there is a size for the specified column.
* @param string $name
* @return boolean
*/
public function hasColumnSize($name)
{
return isset($this->indexColumnSizes[$name]);
}
/**
* Returns the size for the specified column, if given.
* @param string $name
* @return numeric The size or NULL
*/
public function getColumnSize($name)
{
if (isset($this->indexColumnSizes[$name])) {
return $this->indexColumnSizes[$name];
}
return null; // just to be explicit
}
/**
* @see #getColumnList()
* @deprecated Use getColumnList() instead (which is not deprecated too!)
*/
public function getIndexColumnList()
{
return $this->getColumnList();
}
/**
* Return a comma delimited string of the columns which compose this index.
* @deprecated because Column::makeList() is deprecated; use the array-returning getColumns() and DDLBuilder->getColumnList() instead instead.
*/
public function getColumnList()
{
return Column::makeList($this->getColumns(), $this->getTable()->getDatabase()->getPlatform());
}
/**
* @see #getColumns()
* @deprecated Use getColumns() instead.
*/
public function getIndexColumns()
{
return $this->getColumns();
}
/**
* Check whether the index has columns.
* @return boolean
*/
public function hasColumns()
{
return count($this->indexColumns) > 0;
}
/**
* Return the list of local columns. You should not edit this list.
* @return array string[]
*/
public function getColumns()
{
return $this->indexColumns;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$idxNode = $node->appendChild($doc->createElement('index'));
$idxNode->setAttribute('name', $this->getName());
foreach ($this->indexColumns as $colname) {
$idxColNode = $idxNode->appendChild($doc->createElement('index-column'));
$idxColNode->setAttribute('name', $colname);
}
foreach ($this->vendorInfos as $vi) {
$vi->appendXml($idxNode);
}
}
}

View file

@ -0,0 +1,147 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
/**
* A Class for information regarding possible objects representing a table
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author John McNally <jmcnally@collab.net> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class Inheritance extends XMLElement
{
private $key;
private $className;
private $pkg;
private $ancestor;
private $parent;
/**
* Sets up the Inheritance object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->key = $this->getAttribute("key");
$this->className = $this->getAttribute("class");
$this->pkg = $this->getAttribute("package");
$this->ancestor = $this->getAttribute("extends");
}
/**
* Get the value of key.
* @return value of key.
*/
public function getKey()
{
return $this->key;
}
/**
* Set the value of key.
* @param v Value to assign to key.
*/
public function setKey($v)
{
$this->key = $v;
}
/**
* Get the value of parent.
* @return value of parent.
*/
public function getColumn()
{
return $this->parent;
}
/**
* Set the value of parent.
* @param v Value to assign to parent.
*/
public function setColumn(Column $v)
{
$this->parent = $v;
}
/**
* Get the value of className.
* @return value of className.
*/
public function getClassName()
{
return $this->className;
}
/**
* Set the value of className.
* @param v Value to assign to className.
*/
public function setClassName($v)
{
$this->className = $v;
}
/**
* Get the value of package.
* @return value of package.
*/
public function getPackage()
{
return $this->pkg;
}
/**
* Set the value of package.
* @param v Value to assign to package.
*/
public function setPackage($v)
{
$this->pkg = $v;
}
/**
* Get the value of ancestor.
* @return value of ancestor.
*/
public function getAncestor()
{
return $this->ancestor;
}
/**
* Set the value of ancestor.
* @param v Value to assign to ancestor.
*/
public function setAncestor($v)
{
$this->ancestor = $v;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$inherNode = $node->appendChild($doc->createElement('inheritance'));
$inherNode->setAttribute('key', $this->key);
$inherNode->setAttribute('class', $this->className);
if ($this->ancestor !== null) {
$inherNode->setAttribute('extends', $this->ancestor);
}
}
}

View file

@ -0,0 +1,77 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'exception/EngineException.php';
require_once 'model/NameGenerator.php';
require_once 'model/PhpNameGenerator.php';
require_once 'model/ConstraintNameGenerator.php';
/**
* A name generation factory.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Daniel Rall <dlr@finemaltcoding.com> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class NameFactory
{
/**
* The class name of the PHP name generator.
*/
const PHP_GENERATOR = 'PhpNameGenerator';
/**
* The fully qualified class name of the constraint name generator.
*/
const CONSTRAINT_GENERATOR = 'ConstraintNameGenerator';
/**
* The single instance of this class.
*/
private static $instance;
/**
* The cache of <code>NameGenerator</code> algorithms in use for
* name generation, keyed by fully qualified class name.
*/
private static $algorithms = array();
/**
* Factory method which retrieves an instance of the named generator.
*
* @param name The fully qualified class name of the name
* generation algorithm to retrieve.
*/
protected static function getAlgorithm($name)
{
if (!isset(self::$algorithms[$name])) {
self::$algorithms[$name] = new $name();
}
return self::$algorithms[$name];
}
/**
* Given a list of <code>String</code> objects, implements an
* algorithm which produces a name.
*
* @param string $algorithmName The fully qualified class name of the {@link NameGenerator}
* implementation to use to generate names.
* @param array $inputs Inputs used to generate a name.
* @return The generated name.
* @throws EngineException
*/
public static function generateName($algorithmName, $inputs)
{
$algorithm = self::getAlgorithm($algorithmName);
return $algorithm->generateName($inputs);
}
}

View file

@ -0,0 +1,73 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* The generic interface to a name generation algorithm.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Daniel Rall <dlr@finemaltcoding.com> (Torque)
* @author Byron Foster <byron_foster@yahoo.com> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
interface NameGenerator
{
/**
* The character used by most implementations as the separator
* between name elements.
*/
const STD_SEPARATOR_CHAR = '_';
/**
* Traditional method for converting schema table and column names
* to PHP names. The <code>CONV_METHOD_XXX</code> constants
* define how names for columns and tables in the database schema
* will be converted to PHP source names.
*
* @see PhpNameGenerator::underscoreMethod()
*/
const CONV_METHOD_UNDERSCORE = "underscore";
/**
* Heavier method for converting schema table and column names
* to PHP names. Similar to {@link #CONV_METHOD_UNDERSCORE} but
* this one will pass only letters and numbers through and will
* use as separator any character that is not a letter or a number
* inside the string to be converted. The <code>CONV_METHOD_XXX</code>
* constants define how names for columns and tales in the
* database schema will be converted to PHP source names.
*/
const CONV_METHOD_CLEAN = "clean";
/**
* Similar to {@link #CONV_METHOD_UNDERSCORE} except nothing is
* converted to lowercase.
*
* @see PhpNameGenerator::phpnameMethod()
*/
const CONV_METHOD_PHPNAME = "phpname";
/**
* Specifies no modification when converting from a schema column
* or table name to a PHP name.
*/
const CONV_METHOD_NOCHANGE = "nochange";
/**
* Given a list of <code>String</code> objects, implements an
* algorithm which produces a name.
*
* @param inputs Inputs used to generate a name.
* @return The generated name.
* @throws EngineException
*/
public function generateName($inputs);
}

View file

@ -0,0 +1,167 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/NameGenerator.php';
/**
* A <code>NameGenerator</code> implementation for PHP-esque names.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Daniel Rall <dlr@finemaltcoding.com> (Torque)
* @author Byron Foster <byron_foster@yahoo.com> (Torque)
* @author Bernd Goldschmidt <bgoldschmidt@rapidsoft.de>
* @version $Revision: 1793 $
* @package propel.generator.model
*/
class PhpNameGenerator implements NameGenerator
{
/**
* <code>inputs</code> should consist of two (three) elements, the
* original name of the database element and the method for
* generating the name.
* The optional third element may contain a prefix that will be
* stript from name prior to generate the resulting name.
* There are currently three methods:
* <code>CONV_METHOD_NOCHANGE</code> - xml names are converted
* directly to php names without modification.
* <code>CONV_METHOD_UNDERSCORE</code> will capitalize the first
* letter, remove underscores, and capitalize each letter before
* an underscore. All other letters are lowercased. "phpname"
* works the same as the <code>CONV_METHOD_PHPNAME</code> method
* but will not lowercase any characters.
*
* @param inputs list expected to contain two (optional: three) parameters,
* element 0 contains name to convert, element 1 contains method for conversion,
* optional element 2 contains prefix to be striped from name
* @return The generated name.
* @see NameGenerator
*/
public function generateName($inputs)
{
$schemaName = $inputs[0];
$method = $inputs[1];
if (count($inputs)>2) {
$prefix = $inputs[2];
if ($prefix != '' && substr($schemaName, 0, strlen($prefix)) == $prefix) {
$schemaName = substr($schemaName, strlen($prefix));
}
}
$phpName = null;
switch ($method) {
case self::CONV_METHOD_CLEAN:
$phpName = $this->cleanMethod($schemaName);
break;
case self::CONV_METHOD_PHPNAME:
$phpName = $this->phpnameMethod($schemaName);
break;
case self::CONV_METHOD_NOCHANGE:
$phpName = $this->nochangeMethod($schemaName);
break;
case self::CONV_METHOD_UNDERSCORE:
default:
$phpName = $this->underscoreMethod($schemaName);
}
return $phpName;
}
/**
* Converts a database schema name to php object name by Camelization.
* Removes <code>STD_SEPARATOR_CHAR</code>, capitilizes first letter
* of name and each letter after the <code>STD_SEPERATOR</code>,
* converts the rest of the letters to lowercase.
*
* This method should be named camelizeMethod() for clarity
*
* my_CLASS_name -> MyClassName
*
* @param string $schemaName name to be converted.
* @return string Converted name.
* @see NameGenerator
* @see #underscoreMethod()
*/
protected function underscoreMethod($schemaName)
{
$name = "";
$tok = strtok($schemaName, self::STD_SEPARATOR_CHAR);
while ($tok) {
$name .= ucfirst(strtolower($tok));
$tok = strtok(self::STD_SEPARATOR_CHAR);
}
return $name;
}
/**
* Converts a database schema name to php object name. Removes
* any character that is not a letter or a number and capitilizes
* first letter of the name, the first letter of each alphanumeric
* block and converts the rest of the letters to lowercase.
*
* T$NAMA$RFO_max => TNamaRfoMax
*
* @param string $schemaName name to be converted.
* @return string Converted name.
* @see NameGenerator
* @see #underscoreMethod()
*/
protected function cleanMethod($schemaName)
{
$name = "";
$regexp = '/([a-z0-9]+)/i';
$matches = array();
if (preg_match_all($regexp, $schemaName, $matches)) {
foreach($matches[1] AS $tok) {
$name .= ucfirst(strtolower($tok));
}
} else {
return $schemaName;
}
return $name;
}
/**
* Converts a database schema name to php object name. Operates
* same as underscoreMethod but does not convert anything to
* lowercase.
*
* my_CLASS_name -> MyCLASSName
*
* @param string $schemaName name to be converted.
* @return string Converted name.
* @see NameGenerator
* @see #underscoreMethod(String)
*/
protected function phpnameMethod($schemaName)
{
$name = "";
$tok = strtok($schemaName, self::STD_SEPARATOR_CHAR);
while ($tok !== false) {
$name .= ucfirst($tok);
$tok = strtok(self::STD_SEPARATOR_CHAR);
}
return $name;
}
/**
* Converts a database schema name to PHP object name. In this
* case no conversion is made.
*
* @param string $name name to be converted.
* @return string The <code>name</code> parameter, unchanged.
*/
protected function nochangeMethod($name)
{
return $name;
}
}

View file

@ -0,0 +1,343 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
/**
* A class that maps PropelTypes to PHP native types, PDO types (and Creole types).
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class PropelTypes
{
const CHAR = "CHAR";
const VARCHAR = "VARCHAR";
const LONGVARCHAR = "LONGVARCHAR";
const CLOB = "CLOB";
const CLOB_EMU = "CLOB_EMU";
const NUMERIC = "NUMERIC";
const DECIMAL = "DECIMAL";
const TINYINT = "TINYINT";
const SMALLINT = "SMALLINT";
const INTEGER = "INTEGER";
const BIGINT = "BIGINT";
const REAL = "REAL";
const FLOAT = "FLOAT";
const DOUBLE = "DOUBLE";
const BINARY = "BINARY";
const VARBINARY = "VARBINARY";
const LONGVARBINARY = "LONGVARBINARY";
const BLOB = "BLOB";
const DATE = "DATE";
const TIME = "TIME";
const TIMESTAMP = "TIMESTAMP";
const BU_DATE = "BU_DATE";
const BU_TIMESTAMP = "BU_TIMESTAMP";
const BOOLEAN = "BOOLEAN";
const BOOLEAN_EMU = "BOOLEAN_EMU";
private static $TEXT_TYPES = array(
self::CHAR, self::VARCHAR, self::LONGVARCHAR, self::CLOB, self::DATE, self::TIME, self::TIMESTAMP, self::BU_DATE, self::BU_TIMESTAMP
);
private static $LOB_TYPES = array(
self::VARBINARY, self::LONGVARBINARY, self::BLOB
);
private static $TEMPORAL_TYPES = array(
self::DATE, self::TIME, self::TIMESTAMP, self::BU_DATE, self::BU_TIMESTAMP
);
private static $NUMERIC_TYPES = array(
self::SMALLINT, self::TINYINT, self::INTEGER, self::BIGINT, self::FLOAT, self::DOUBLE, self::NUMERIC, self::DECIMAL, self::REAL
);
private static $BOOLEAN_TYPES = array(
self::BOOLEAN, self::BOOLEAN_EMU
);
const CHAR_NATIVE_TYPE = "string";
const VARCHAR_NATIVE_TYPE = "string";
const LONGVARCHAR_NATIVE_TYPE = "string";
const CLOB_NATIVE_TYPE = "string";
const CLOB_EMU_NATIVE_TYPE = "resource";
const NUMERIC_NATIVE_TYPE = "string";
const DECIMAL_NATIVE_TYPE = "string";
const TINYINT_NATIVE_TYPE = "int";
const SMALLINT_NATIVE_TYPE = "int";
const INTEGER_NATIVE_TYPE = "int";
const BIGINT_NATIVE_TYPE = "string";
const REAL_NATIVE_TYPE = "double";
const FLOAT_NATIVE_TYPE = "double";
const DOUBLE_NATIVE_TYPE = "double";
const BINARY_NATIVE_TYPE = "string";
const VARBINARY_NATIVE_TYPE = "string";
const LONGVARBINARY_NATIVE_TYPE = "string";
const BLOB_NATIVE_TYPE = "resource";
const BU_DATE_NATIVE_TYPE = "string";
const DATE_NATIVE_TYPE = "string";
const TIME_NATIVE_TYPE = "string";
const TIMESTAMP_NATIVE_TYPE = "string";
const BU_TIMESTAMP_NATIVE_TYPE = "string";
const BOOLEAN_NATIVE_TYPE = "boolean";
const BOOLEAN_EMU_NATIVE_TYPE = "boolean";
/**
* Mapping between Propel types and PHP native types.
*
* @var array
*/
private static $propelToPHPNativeMap = array(
self::CHAR => self::CHAR_NATIVE_TYPE,
self::VARCHAR => self::VARCHAR_NATIVE_TYPE,
self::LONGVARCHAR => self::LONGVARCHAR_NATIVE_TYPE,
self::CLOB => self::CLOB_NATIVE_TYPE,
self::CLOB_EMU => self::CLOB_EMU_NATIVE_TYPE,
self::NUMERIC => self::NUMERIC_NATIVE_TYPE,
self::DECIMAL => self::DECIMAL_NATIVE_TYPE,
self::TINYINT => self::TINYINT_NATIVE_TYPE,
self::SMALLINT => self::SMALLINT_NATIVE_TYPE,
self::INTEGER => self::INTEGER_NATIVE_TYPE,
self::BIGINT => self::BIGINT_NATIVE_TYPE,
self::REAL => self::REAL_NATIVE_TYPE,
self::FLOAT => self::FLOAT_NATIVE_TYPE,
self::DOUBLE => self::DOUBLE_NATIVE_TYPE,
self::BINARY => self::BINARY_NATIVE_TYPE,
self::VARBINARY => self::VARBINARY_NATIVE_TYPE,
self::LONGVARBINARY => self::LONGVARBINARY_NATIVE_TYPE,
self::BLOB => self::BLOB_NATIVE_TYPE,
self::DATE => self::DATE_NATIVE_TYPE,
self::BU_DATE => self::BU_DATE_NATIVE_TYPE,
self::TIME => self::TIME_NATIVE_TYPE,
self::TIMESTAMP => self::TIMESTAMP_NATIVE_TYPE,
self::BU_TIMESTAMP => self::BU_TIMESTAMP_NATIVE_TYPE,
self::BOOLEAN => self::BOOLEAN_NATIVE_TYPE,
self::BOOLEAN_EMU => self::BOOLEAN_EMU_NATIVE_TYPE,
);
/**
* Mapping between Propel types and Creole types (for rev-eng task)
*
* @var array
*/
private static $propelTypeToCreoleTypeMap = array(
self::CHAR => self::CHAR,
self::VARCHAR => self::VARCHAR,
self::LONGVARCHAR => self::LONGVARCHAR,
self::CLOB => self::CLOB,
self::NUMERIC => self::NUMERIC,
self::DECIMAL => self::DECIMAL,
self::TINYINT => self::TINYINT,
self::SMALLINT => self::SMALLINT,
self::INTEGER => self::INTEGER,
self::BIGINT => self::BIGINT,
self::REAL => self::REAL,
self::FLOAT => self::FLOAT,
self::DOUBLE => self::DOUBLE,
self::BINARY => self::BINARY,
self::VARBINARY => self::VARBINARY,
self::LONGVARBINARY => self::LONGVARBINARY,
self::BLOB => self::BLOB,
self::DATE => self::DATE,
self::TIME => self::TIME,
self::TIMESTAMP => self::TIMESTAMP,
self::BOOLEAN => self::BOOLEAN,
self::BOOLEAN_EMU => self::BOOLEAN_EMU,
// These are pre-epoch dates, which we need to map to String type
// since they cannot be properly handled using strtotime() -- or even numeric
// timestamps on Windows.
self::BU_DATE => self::VARCHAR,
self::BU_TIMESTAMP => self::VARCHAR,
);
/**
* Mapping between Propel types and PDO type contants (for prepared statement setting).
*
* @var array
*/
private static $propelTypeToPDOTypeMap = array(
self::CHAR => PDO::PARAM_STR,
self::VARCHAR => PDO::PARAM_STR,
self::LONGVARCHAR => PDO::PARAM_STR,
self::CLOB => PDO::PARAM_STR,
self::CLOB_EMU => PDO::PARAM_STR,
self::NUMERIC => PDO::PARAM_INT,
self::DECIMAL => PDO::PARAM_STR,
self::TINYINT => PDO::PARAM_INT,
self::SMALLINT => PDO::PARAM_INT,
self::INTEGER => PDO::PARAM_INT,
self::BIGINT => PDO::PARAM_INT,
self::REAL => PDO::PARAM_STR,
self::FLOAT => PDO::PARAM_STR,
self::DOUBLE => PDO::PARAM_STR,
self::BINARY => PDO::PARAM_STR,
self::VARBINARY => PDO::PARAM_LOB,
self::LONGVARBINARY => PDO::PARAM_LOB,
self::BLOB => PDO::PARAM_LOB,
self::DATE => PDO::PARAM_STR,
self::TIME => PDO::PARAM_STR,
self::TIMESTAMP => PDO::PARAM_STR,
self::BOOLEAN => PDO::PARAM_BOOL,
self::BOOLEAN_EMU => PDO::PARAM_INT,
// These are pre-epoch dates, which we need to map to String type
// since they cannot be properly handled using strtotime() -- or even numeric
// timestamps on Windows.
self::BU_DATE => PDO::PARAM_STR,
self::BU_TIMESTAMP => PDO::PARAM_STR,
);
/**
* Return native PHP type which corresponds to the
* Creole type provided. Use in the base object class generation.
*
* @param $propelType The Propel type name.
* @return string Name of the native PHP type
*/
public static function getPhpNative($propelType)
{
return self::$propelToPHPNativeMap[$propelType];
}
/**
* Returns the correct Creole type _name_ for propel added types
*
* @param $type the propel added type.
* @return string Name of the the correct Creole type (e.g. "VARCHAR").
*/
public static function getCreoleType($type)
{
return self::$propelTypeToCreoleTypeMap[$type];
}
/**
* Resturns the PDO type (PDO::PARAM_* constant) value.
* @return int
*/
public static function getPDOType($type)
{
return self::$propelTypeToPDOTypeMap[$type];
}
/**
* Returns Propel type constant corresponding to Creole type code.
* Used but Propel Creole task.
*
* @param int $sqlType The Creole SQL type constant.
* @return string The Propel type to use or NULL if none found.
*/
public static function getPropelType($sqlType)
{
if (isset(self::$creoleToPropelTypeMap[$sqlType])) {
return self::$creoleToPropelTypeMap[$sqlType];
}
}
/**
* Get array of Propel types.
*
* @return array string[]
*/
public static function getPropelTypes()
{
return array_keys(self::$propelTypeToCreoleTypeMap);
}
/**
* Whether passed type is a temporal (date/time/timestamp) type.
*
* @param string $type Propel type
* @return boolean
*/
public static function isTemporalType($type)
{
return in_array($type, self::$TEMPORAL_TYPES);
}
/**
* Returns true if values for the type need to be quoted.
*
* @param string $type The Propel type to check.
* @return boolean True if values for the type need to be quoted.
*/
public static function isTextType($type)
{
return in_array($type, self::$TEXT_TYPES);
}
/**
* Returns true if values for the type are numeric.
*
* @param string $type The Propel type to check.
* @return boolean True if values for the type need to be quoted.
*/
public static function isNumericType($type)
{
return in_array($type, self::$NUMERIC_TYPES);
}
/**
* Returns true if values for the type are boolean.
*
* @param string $type The Propel type to check.
* @return boolean True if values for the type need to be quoted.
*/
public static function isBooleanType($type)
{
return in_array($type, self::$BOOLEAN_TYPES);
}
/**
* Returns true if type is a LOB type (i.e. would be handled by Blob/Clob class).
* @param string $type Propel type to check.
* @return boolean
*/
public static function isLobType($type)
{
return in_array($type, self::$LOB_TYPES);
}
/**
* Convenience method to indicate whether a passed-in PHP type is a primitive.
*
* @param string $phpType The PHP type to check
* @return boolean Whether the PHP type is a primitive (string, int, boolean, float)
*/
public static function isPhpPrimitiveType($phpType)
{
return in_array($phpType, array("boolean", "int", "double", "float", "string"));
}
/**
* Convenience method to indicate whether a passed-in PHP type is a numeric primitive.
*
* @param string $phpType The PHP type to check
* @return boolean Whether the PHP type is a primitive (string, int, boolean, float)
*/
public static function isPhpPrimitiveNumericType($phpType)
{
return in_array($phpType, array("boolean", "int", "double", "float"));
}
/**
* Convenience method to indicate whether a passed-in PHP type is an object.
*
* @param string $phpType The PHP type to check
* @return boolean Whether the PHP type is a primitive (string, int, boolean, float)
*/
public static function isPhpObjectType($phpType)
{
return (!self::isPhpPrimitiveType($phpType) && !in_array($phpType, array("resource", "array")));
}
}

View file

@ -0,0 +1,194 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
/**
* Data about a validation rule used in an application.
*
* @author Michael Aichler <aichler@mediacluster.de> (Propel)
* @author John McNally <jmcnally@collab.net> (Intake)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class Rule extends XMLElement
{
private $name;
private $value;
private $message;
private $validator;
private $classname;
/**
* Sets up the Rule object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->name = $this->getAttribute("name");
$this->value = $this->getAttribute("value");
$this->classname = $this->getAttribute("class");
/*
* Set some default values if they are not specified.
* This is escpecially useful for maxLength; the size
* is already known by the column and this way it is
* not necessary to manage the same size two times.
*
* Currently there is only one such supported default:
* - maxLength value = column max length
* (this default cannot be easily set at runtime w/o changing
* design of class system in undesired ways)
*/
if ($this->value === null) {
switch($this->name) {
case 'maxLength':
$this->value = $this->validator->getColumn()->getSize();
break;
}
}
$this->message = $this->getAttribute("message");
}
/**
* Sets the owning validator for this rule.
* @param Validator $validator
* @see Validator::addRule()
*/
public function setValidator(Validator $validator)
{
$this->validator = $validator;
}
/**
* Gets the owning validator for this rule.
* @return Validator
*/
public function getValidator()
{
return $this->validator;
}
/**
* Sets the dot-path name of class to use for rule.
* If no class is specified in XML, then a classname will
* be built based on the 'name' attrib.
* @param string $classname dot-path classname (e.g. myapp.propel.MyValidator)
*/
public function setClass($classname)
{
$this->classname = $classname;
}
/**
* Gets the dot-path name of class to use for rule.
* If no class was specified, this method will build a default classname
* based on the 'name' attribute. E.g. 'maxLength' -> 'propel.validator.MaxLengthValidator'
* @return string dot-path classname (e.g. myapp.propel.MyValidator)
*/
public function getClass()
{
if ($this->classname === null && $this->name !== null) {
return "propel.validator." . ucfirst($this->name) . "Validator";
}
return $this->classname;
}
/**
* Sets the name of the validator for this rule.
* This name is used to build the classname if none was specified.
* @param string $name Validator name for this rule (e.g. "maxLength", "required").
* @see getClass()
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Gets the name of the validator for this rule.
* @return string Validator name for this rule (e.g. "maxLength", "required").
*/
public function getName()
{
return $this->name;
}
/**
* Sets the value parameter for this validator rule.
* Note: not all validators need a value parameter (e.g. 'required' validator
* does not).
* @param string $value
*/
public function setValue($value)
{
$this->value = $value;
}
/**
* Gets the value parameter for this validator rule.
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Sets the message that will be displayed to the user if validation fails.
* This message may be a Gettext msgid (if translation="gettext") or some other
* id for an alternative not-yet-supported translation system. It may also
* be a simple, single-language string.
* @param string $message
* @see setTranslation()
*/
public function setMessage($message)
{
$this->message = $message;
}
/**
* Gets the message that will be displayed to the user if validation fails.
* This message may be a Gettext msgid (if translation="gettext") or some other
* id for an alternative not-yet-supported translation system. It may also
* be a simple, single-language string.
* @return string
* @see setTranslation()
*/
public function getMessage()
{
$message = str_replace('${value}', $this->getValue(), $this->message);
return $message;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$ruleNode = $node->appendChild($doc->createElement('rule'));
$ruleNode->setAttribute('name', $this->getName());
if ($this->getValue() !== null) {
$ruleNode->setAttribute('value', $this->getValue());
}
if ($this->classname !== null) {
$ruleNode->setAttribute('class', $this->getClass());
}
$ruleNode->setAttribute('message', $this->getMessage());
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,58 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/Index.php';
/**
* Information about unique columns of a table. This class assumes
* that in the underlying RDBMS, unique constraints and unique indices
* are roughly equivalent. For example, adding a unique constraint to
* a column also creates an index on that column (this is known to be
* true for MySQL and Oracle).
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Jason van Zyl <jvanzyl@apache.org> (Torque)
* @author Daniel Rall <dlr@collab.net> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class Unique extends Index
{
/**
* Returns <code>true</code>.
*/
public function isUnique()
{
return true;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$uniqueNode = $node->appendChild($doc->createElement('unique'));
$uniqueNode->setAttribute('name', $this->getName());
$columns = $this->getColumns();
foreach ($this->getColumns() as $colname) {
$uniqueColNode = $uniqueNode->appendChild($doc->createElement('unique-column'));
$uniqueColNode->setAttribute('name', $colname);
}
foreach ($this->vendorInfos as $vi) {
$vi->appendXml($uniqueNode);
}
}
}

View file

@ -0,0 +1,184 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
require_once 'exception/EngineException.php';
require_once 'model/PropelTypes.php';
require_once 'model/Rule.php';
/**
* Validator.
*
* @author Michael Aichler <aichler@mediacluster.de> (Propel)
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class Validator extends XMLElement
{
const TRANSLATE_NONE = "none";
const TRANSLATE_GETTEXT = "gettext";
/**
* The column this validator applies to.
*
* @var Column
*/
private $column;
/**
* The rules for the validation.
*
* @var array Rule[]
*/
private $ruleList = array();
/**
* The translation mode.
*
* @var string
*/
private $translate;
/**
* Parent table.
*
* @var Table
*/
private $table;
/**
* Sets up the Validator object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->column = $this->getTable()->getColumn($this->getAttribute("column"));
$this->translate = $this->getAttribute("translate", $this->getTable()->getDatabase()->getDefaultTranslateMethod());;
}
/**
* Add a Rule to this validator.
* Supports two signatures:
* - addRule(Rule $rule)
* - addRule(array $attribs)
* @param mixed $data Rule object or XML attribs (array) from <rule/> element.
* @return Rule The added Rule.
*/
public function addRule($data)
{
if ($data instanceof Rule) {
$rule = $data; // alias
$rule->setValidator($this);
$this->ruleList[] = $rule;
return $rule;
}
else {
$rule = new Rule();
$rule->setValidator($this);
$rule->loadFromXML($data);
return $this->addRule($rule); // call self w/ different param
}
}
/**
* Gets an array of all added rules for this validator.
* @return array Rule[]
*/
public function getRules()
{
return $this->ruleList;
}
/**
* Gets the name of the column that this Validator applies to.
* @return string
*/
public function getColumnName()
{
return $this->column->getName();
}
/**
* Sets the Column object that this validator applies to.
* @param Column $column
* @see Table::addValidator()
*/
public function setColumn(Column $column)
{
$this->column = $column;
}
/**
* Gets the Column object that this validator applies to.
* @return Column
*/
public function getColumn()
{
return $this->column;
}
/**
* Set the owning Table.
* @param Table $table
*/
public function setTable(Table $table)
{
$this->table = $table;
}
/**
* Get the owning Table.
* @return Table
*/
public function getTable()
{
return $this->table;
}
/**
* Set the translation mode to use for the message.
* Currently only "gettext" and "none" are supported. The default is "none".
* @param string $method Translation method ("gettext", "none").
*/
public function setTranslate($method)
{
$this->translate = $method;
}
/**
* Get the translation mode to use for the message.
* Currently only "gettext" and "none" are supported. The default is "none".
* @return string Translation method ("gettext", "none").
*/
public function getTranslate()
{
return $this->translate;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$valNode = $node->appendChild($doc->createElement('validator'));
$valNode->setAttribute('column', $this->getColumnName());
if ($this->translate !== null) {
$valNode->setAttribute('translate', $this->translate);
}
foreach ($this->ruleList as $rule) {
$rule->appendXml($valNode);
}
}
}

View file

@ -0,0 +1,172 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/XMLElement.php';
require_once 'exception/EngineException.php';
/**
* Object to hold vendor-specific info.
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1612 $
* @package propel.generator.model
*/
class VendorInfo extends XMLElement
{
/**
* The vendor RDBMS type.
*
* @var string
*/
private $type;
/**
* Vendor parameters.
*
* @var array
*/
private $parameters = array();
/**
* Creates a new VendorInfo instance.
*
* @param string $type RDBMS type (optional)
*/
public function __construct($type = null)
{
$this->type = $type;
}
/**
* Sets up this object based on the attributes that were passed to loadFromXML().
* @see parent::loadFromXML()
*/
protected function setupObject()
{
$this->type = $this->getAttribute("type");
}
/**
* Set RDBMS type for this vendor-specific info.
*
* @param string $v
*/
public function setType($v)
{
$this->type = $v;
}
/**
* Get RDBMS type for this vendor-specific info.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Adds a new vendor parameter to this object.
* @param array $attrib Attributes from XML.
*/
public function addParameter($attrib)
{
$name = $attrib["name"];
$this->parameters[$name] = $attrib["value"];
}
/**
* Sets parameter value.
*
* @param string $name
* @param mixed $value The value for the parameter.
*/
public function setParameter($name, $value)
{
$this->parameters[$name] = $value;
}
/**
* Gets parameter value.
*
* @param string $name
* @return mixed Paramter value.
*/
public function getParameter($name)
{
if (isset($this->parameters[$name])) {
return $this->parameters[$name];
}
return null; // just to be explicit
}
/**
* Whether parameter exists.
*
* @param string $name
*/
public function hasParameter($name)
{
return isset($this->parameters[$name]);
}
/**
* Sets assoc array of parameters for venfor specific info.
*
* @param array $params Paramter data.
*/
public function setParameters(array $params = array())
{
$this->parameters = $params;
}
/**
* Gets assoc array of parameters for venfor specific info.
*
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* Gets a new merged VendorInfo object.
* @param VendorInfo $info
* @return VendorInfo new object with merged parameters
*/
public function getMergedVendorInfo(VendorInfo $merge)
{
$newParams = array_merge($this->getParameters(), $merge->getParameters());
$newInfo = new VendorInfo($this->getType());
$newInfo->setParameters($newParams);
return $newInfo;
}
/**
* @see XMLElement::appendXml(DOMNode)
*/
public function appendXml(DOMNode $node)
{
$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;
$vendorNode = $node->appendChild($doc->createElement("vendor"));
$vendorNode->setAttribute("type", $this->getType());
foreach ($this->parameters as $key => $value) {
$parameterNode = $doc->createElement("parameter");
$parameterNode->setAttribute("name", $key);
$parameterNode->setAttribute("value", $value);
$vendorNode->appendChild($parameterNode);
}
}
}

View file

@ -0,0 +1,182 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'model/VendorInfo.php';
/**
* An abstract class for elements represented by XML tags (e.g. Column, Table).
*
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1612 $
* @package propel.generator.model
*/
abstract class XMLElement
{
/**
* The name => value attributes from XML.
*
* @var array
*/
protected $attributes = array();
/**
* Any associated vendor-specific information objects.
*
* @var array VendorInfo[]
*/
protected $vendorInfos = array();
/**
* Replaces the old loadFromXML() so that we can use loadFromXML() to load the attribs into the class.
*/
abstract protected function setupObject();
/**
* This is the entry point method for loading data from XML.
* It calls a setupObject() method that must be implemented by the child class.
* @param array $attributes The attributes for the XML tag.
*/
public function loadFromXML($attributes)
{
$this->attributes = array_change_key_case($attributes, CASE_LOWER);
$this->setupObject();
}
/**
* Returns the assoc array of attributes.
* All attribute names (keys) are lowercase.
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Gets a particular attribute by [case-insensitive] name.
* If attribute is not set then the $defaultValue is returned.
* @param string $name The [case-insensitive] name of the attribute to lookup.
* @param mixed $defaultValue The default value to use in case the attribute is not set.
* @return mixed The value of the attribute or $defaultValue if not set.
*/
public function getAttribute($name, $defaultValue = null)
{
$name = strtolower($name);
if (isset($this->attributes[$name])) {
return $this->attributes[$name];
} else {
return $defaultValue;
}
}
/**
* Converts value specified in XML to a boolean value.
* This is to support the default value when used w/ a boolean column.
* @return value
*/
protected function booleanValue($val)
{
if (is_numeric($val)) {
return (bool) $val;
} else {
return (in_array(strtolower($val), array('true', 't', 'y', 'yes'), true) ? true : false);
}
}
/**
* Appends DOM elements to represent this object in XML.
* @param DOMNode $node
*/
abstract public function appendXml(DOMNode $node);
/**
* Sets an associated VendorInfo object.
*
* @param mixed $data VendorInfo object or XML attrib data (array)
* @return VendorInfo
*/
public function addVendorInfo($data)
{
if ($data instanceof VendorInfo) {
$vi = $data;
$this->vendorInfos[$vi->getType()] = $vi;
return $vi;
} else {
$vi = new VendorInfo();
$vi->loadFromXML($data);
return $this->addVendorInfo($vi); // call self w/ different param
}
}
/**
* Gets the any associated VendorInfo object.
* @return VendorInfo
*/
public function getVendorInfoForType($type)
{
if (isset($this->vendorInfos[$type])) {
return $this->vendorInfos[$type];
} else {
// return an empty object
return new VendorInfo();
}
}
/**
* Find the best class name for a given behavior
* Looks in build.properties for path like propel.behavior.[bname].class
* If not found, tries to autoload [Bname]Behavior
* If no success, returns 'Behavior'
*
* @param string $bname behavior name, e.g. 'timestampable'
* @return string behavior class name, e.g. 'TimestampableBehavior'
*/
public function getConfiguredBehavior($bname)
{
if ($config = $this->getGeneratorConfig()) {
if ($class = $config->getConfiguredBehavior($bname)) {
return $class;
}
}
// first fallback: maybe the behavior is loaded or autoloaded
$gen = new PhpNameGenerator();
if(class_exists($class = $gen->generateName($bname, PhpNameGenerator::CONV_METHOD_PHPNAME) . 'Behavior')) {
return $class;
}
// second fallback: use parent behavior class (mostly for unit tests)
return 'Behavior';
}
/**
* String representation of the current object.
*
* This is an xml representation with the XML declaration removed.
*
* @see appendXml()
*/
public function toString()
{
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$this->appendXml($doc);
$xmlstr = $doc->saveXML();
return trim(preg_replace('/<\?xml.*?\?>/', '', $xmlstr));
}
/**
* Magic string method
* @see toString()
*/
public function __toString()
{
return $this->toString();
}
}

View file

@ -0,0 +1,299 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'platform/Platform.php';
require_once 'model/Domain.php';
require_once 'model/PropelTypes.php';
/**
* Default implementation for the Platform interface.
*
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.platform
*/
class DefaultPlatform implements Platform
{
/**
* Mapping from Propel types to Domain objects.
*
* @var array
*/
protected $schemaDomainMap;
/**
* GeneratorConfig object holding build properties.
*
* @var GeneratorConfig
*/
private $generatorConfig;
/**
* @var PDO Database connection.
*/
private $con;
/**
* Default constructor.
* @param PDO $con Optional database connection to use in this platform.
*/
public function __construct(PDO $con = null)
{
if ($con) $this->setConnection($con);
$this->initialize();
}
/**
* Set the database connection to use for this Platform class.
* @param PDO $con Database connection to use in this platform.
*/
public function setConnection(PDO $con = null)
{
$this->con = $con;
}
/**
* Sets the GeneratorConfig to use in the parsing.
*
* @param GeneratorConfig $config
*/
public function setGeneratorConfig(GeneratorConfig $config)
{
$this->generatorConfig = $config;
}
/**
* Gets the GeneratorConfig option.
*
* @return GeneratorConfig
*/
public function getGeneratorConfig()
{
return $this->generatorConfig;
}
/**
* Gets a specific propel (renamed) property from the build.
*
* @param string $name
* @return mixed
*/
protected function getBuildProperty($name)
{
if ($this->generatorConfig !== null) {
return $this->generatorConfig->getBuildProperty($name);
}
return null;
}
/**
* Returns the database connection to use for this Platform class.
* @return PDO The database connection or NULL if none has been set.
*/
public function getConnection()
{
return $this->con;
}
/**
* Initialize the type -> Domain mapping.
*/
protected function initialize()
{
$this->schemaDomainMap = array();
foreach (PropelTypes::getPropelTypes() as $type) {
$this->schemaDomainMap[$type] = new Domain($type);
}
// BU_* no longer needed, so map these to the DATE/TIMESTAMP domains
$this->schemaDomainMap[PropelTypes::BU_DATE] = new Domain(PropelTypes::DATE);
$this->schemaDomainMap[PropelTypes::BU_TIMESTAMP] = new Domain(PropelTypes::TIMESTAMP);
// Boolean is a bit special, since typically it must be mapped to INT type.
$this->schemaDomainMap[PropelTypes::BOOLEAN] = new Domain(PropelTypes::BOOLEAN, "INTEGER");
}
/**
* Adds a mapping entry for specified Domain.
* @param Domain $domain
*/
protected function setSchemaDomainMapping(Domain $domain)
{
$this->schemaDomainMap[$domain->getType()] = $domain;
}
/**
* Returns the short name of the database type that this platform represents.
* For example MysqlPlatform->getDatabaseType() returns 'mysql'.
* @return string
*/
public function getDatabaseType()
{
$clazz = get_class($this);
$pos = strpos($clazz, 'Platform');
return strtolower(substr($clazz,0,$pos));
}
/**
* @see Platform::getMaxColumnNameLength()
*/
public function getMaxColumnNameLength()
{
return 64;
}
/**
* @see Platform::getNativeIdMethod()
*/
public function getNativeIdMethod()
{
return Platform::IDENTITY;
}
/**
* @see Platform::getDomainForType()
*/
public function getDomainForType($propelType)
{
if (!isset($this->schemaDomainMap[$propelType])) {
throw new EngineException("Cannot map unknown Propel type " . var_export($propelType, true) . " to native database type.");
}
return $this->schemaDomainMap[$propelType];
}
/**
* @return string Returns the SQL fragment to use if null values are disallowed.
* @see Platform::getNullString(boolean)
*/
public function getNullString($notNull)
{
return ($notNull ? "NOT NULL" : "");
}
/**
* @see Platform::getAutoIncrement()
*/
public function getAutoIncrement()
{
return "IDENTITY";
}
/**
* @see Platform::hasScale(String)
*/
public function hasScale($sqlType)
{
return true;
}
/**
* @see Platform::hasSize(String)
*/
public function hasSize($sqlType)
{
return true;
}
/**
* @see Platform::quote()
*/
public function quote($text)
{
if ($this->getConnection()) {
return $this->getConnection()->quote($text);
} else {
return "'" . $this->disconnectedEscapeText($text) . "'";
}
}
/**
* Method to escape text when no connection has been set.
*
* The subclasses can implement this using string replacement functions
* or native DB methods.
*
* @param string $text Text that needs to be escaped.
* @return string
*/
protected function disconnectedEscapeText($text)
{
return str_replace("'", "''", $text);
}
/**
* @see Platform::quoteIdentifier()
*/
public function quoteIdentifier($text)
{
return '"' . $text . '"';
}
/**
* @see Platform::supportsNativeDeleteTrigger()
*/
public function supportsNativeDeleteTrigger()
{
return false;
}
/**
* @see Platform::supportsInsertNullPk()
*/
public function supportsInsertNullPk()
{
return true;
}
/**
* Whether the underlying PDO driver for this platform returns BLOB columns as streams (instead of strings).
* @return boolean
*/
public function hasStreamBlobImpl()
{
return false;
}
/**
* @see Platform::getBooleanString()
*/
public function getBooleanString($b)
{
$b = ($b === true || strtolower($b) === 'true' || $b === 1 || $b === '1' || strtolower($b) === 'y' || strtolower($b) === 'yes');
return ($b ? '1' : '0');
}
/**
* Gets the preferred timestamp formatter for setting date/time values.
* @return string
*/
public function getTimestampFormatter()
{
return DateTime::ISO8601;
}
/**
* Gets the preferred time formatter for setting date/time values.
* @return string
*/
public function getTimeFormatter()
{
return 'H:i:s';
}
/**
* Gets the preferred date formatter for setting date/time values.
* @return string
*/
public function getDateFormatter()
{
return 'Y-m-d';
}
}

View file

@ -0,0 +1,107 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'platform/DefaultPlatform.php';
require_once 'model/Domain.php';
/**
* MS SQL Platform implementation.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.platform
*/
class MssqlPlatform extends DefaultPlatform
{
/**
* Initializes db specific domain mapping.
*/
protected function initialize()
{
parent::initialize();
$this->setSchemaDomainMapping(new Domain(PropelTypes::INTEGER, "INT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BOOLEAN, "INT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DOUBLE, "FLOAT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARCHAR, "TEXT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::CLOB, "TEXT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DATE, "DATETIME"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BU_DATE, "DATETIME"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::TIME, "DATETIME"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::TIMESTAMP, "DATETIME"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BU_TIMESTAMP, "DATETIME"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BINARY, "BINARY(7132)"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::VARBINARY, "IMAGE"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARBINARY, "IMAGE"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BLOB, "IMAGE"));
}
/**
* @see Platform#getMaxColumnNameLength()
*/
public function getMaxColumnNameLength()
{
return 128;
}
/**
* @return Explicitly returns <code>NULL</code> if null values are
* allowed (as recomended by Microsoft).
* @see Platform#getNullString(boolean)
*/
public function getNullString($notNull)
{
return ($notNull ? "NOT NULL" : "NULL");
}
/**
* @see Platform::supportsNativeDeleteTrigger()
*/
public function supportsNativeDeleteTrigger()
{
return true;
}
/**
* @see Platform::supportsInsertNullPk()
*/
public function supportsInsertNullPk()
{
return false;
}
/**
* @see Platform::hasSize(String)
*/
public function hasSize($sqlType)
{
return !("INT" == $sqlType || "TEXT" == $sqlType);
}
/**
* @see Platform::quoteIdentifier()
*/
public function quoteIdentifier($text)
{
return '[' . $text . ']';
}
/**
* Gets the preferred timestamp formatter for setting date/time values.
* @return string
*/
public function getTimestampFormatter()
{
return 'Y-m-d H:i:s';
}
}

View file

@ -0,0 +1,110 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'platform/DefaultPlatform.php';
/**
* MySql Platform implementation.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.platform
*/
class MysqlPlatform extends DefaultPlatform
{
/**
* Initializes db specific domain mapping.
*/
protected function initialize()
{
parent::initialize();
$this->setSchemaDomainMapping(new Domain(PropelTypes::BOOLEAN, "TINYINT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::NUMERIC, "DECIMAL"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARCHAR, "TEXT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BINARY, "BLOB"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::VARBINARY, "MEDIUMBLOB"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARBINARY, "LONGBLOB"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BLOB, "LONGBLOB"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::CLOB, "LONGTEXT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::TIMESTAMP, "DATETIME"));
}
/**
* @see Platform#getAutoIncrement()
*/
public function getAutoIncrement()
{
return "AUTO_INCREMENT";
}
/**
* @see Platform#getMaxColumnNameLength()
*/
public function getMaxColumnNameLength()
{
return 64;
}
/**
* @see Platform::supportsNativeDeleteTrigger()
*/
public function supportsNativeDeleteTrigger()
{
$usingInnoDB = false;
if (class_exists('DataModelBuilder', false))
{
$usingInnoDB = strtolower($this->getBuildProperty('mysqlTableType')) == 'innodb';
}
return $usingInnoDB || false;
}
/**
* @see Platform#hasSize(String)
*/
public function hasSize($sqlType)
{
return !("MEDIUMTEXT" == $sqlType || "LONGTEXT" == $sqlType
|| "BLOB" == $sqlType || "MEDIUMBLOB" == $sqlType
|| "LONGBLOB" == $sqlType);
}
/**
* Escape the string for RDBMS.
* @param string $text
* @return string
*/
public function disconnectedEscapeText($text)
{
if (function_exists('mysql_escape_string')) {
return mysql_escape_string($text);
} else {
return addslashes($text);
}
}
/**
* @see Platform::quoteIdentifier()
*/
public function quoteIdentifier($text)
{
return '`' . $text . '`';
}
/**
* Gets the preferred timestamp formatter for setting date/time values.
* @return string
*/
public function getTimestampFormatter()
{
return 'Y-m-d H:i:s';
}
}

View file

@ -0,0 +1,113 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'platform/DefaultPlatform.php';
/**
* Oracle Platform implementation.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.platform
*/
class OraclePlatform extends DefaultPlatform
{
/**
* Initializes db specific domain mapping.
*/
protected function initialize()
{
parent::initialize();
$this->schemaDomainMap[PropelTypes::BOOLEAN] = new Domain(PropelTypes::BOOLEAN_EMU, "NUMBER", "1", "0");
$this->schemaDomainMap[PropelTypes::CLOB] = new Domain(PropelTypes::CLOB_EMU, "CLOB");
$this->schemaDomainMap[PropelTypes::CLOB_EMU] = $this->schemaDomainMap[PropelTypes::CLOB];
$this->setSchemaDomainMapping(new Domain(PropelTypes::TINYINT, "NUMBER", "3", "0"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::SMALLINT, "NUMBER", "5", "0"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::INTEGER, "NUMBER"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BIGINT, "NUMBER", "20", "0"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::REAL, "NUMBER"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DOUBLE, "FLOAT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DECIMAL, "NUMBER"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::NUMERIC, "NUMBER"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::VARCHAR, "NVARCHAR2"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARCHAR, "NVARCHAR2", "2000"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::TIME, "DATE"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DATE, "DATE"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::TIMESTAMP, "TIMESTAMP"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BINARY, "LONG RAW"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::VARBINARY, "BLOB"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARBINARY, "LONG RAW"));
}
/**
* @see Platform#getMaxColumnNameLength()
*/
public function getMaxColumnNameLength()
{
return 30;
}
/**
* @see Platform#getNativeIdMethod()
*/
public function getNativeIdMethod()
{
return Platform::SEQUENCE;
}
/**
* @see Platform#getAutoIncrement()
*/
public function getAutoIncrement()
{
return "";
}
/**
* @see Platform::supportsNativeDeleteTrigger()
*/
public function supportsNativeDeleteTrigger()
{
return true;
}
/**
* Whether the underlying PDO driver for this platform returns BLOB columns as streams (instead of strings).
* @return boolean
*/
public function hasStreamBlobImpl()
{
return true;
}
/**
* Quotes identifiers used in database SQL.
* @see Platform::quoteIdentifier()
* @param string $text
* @return string Quoted identifier.
*/
public function quoteIdentifier($text)
{
return $text;
}
/**
* Gets the preferred timestamp formatter for setting date/time values.
* @see Platform::getTimestampFormatter()
* @return string
*/
public function getTimestampFormatter()
{
return 'Y-m-d H:i:s';
}
}

View file

@ -0,0 +1,118 @@
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
require_once 'platform/DefaultPlatform.php';
/**
* Postgresql Platform implementation.
*
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
* @version $Revision: 1612 $
* @package propel.generator.platform
*/
class PgsqlPlatform extends DefaultPlatform
{
/**
* Initializes db specific domain mapping.
*/
protected function initialize()
{
parent::initialize();
$this->setSchemaDomainMapping(new Domain(PropelTypes::BOOLEAN, "BOOLEAN"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::TINYINT, "INT2"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::SMALLINT, "INT2"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BIGINT, "INT8"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::REAL, "FLOAT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DOUBLE, "DOUBLE PRECISION"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARCHAR, "TEXT"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BINARY, "BYTEA"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::VARBINARY, "BYTEA"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::LONGVARBINARY, "BYTEA"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::BLOB, "BYTEA"));
$this->setSchemaDomainMapping(new Domain(PropelTypes::CLOB, "TEXT"));
}
/**
* @see Platform#getNativeIdMethod()
*/
public function getNativeIdMethod()
{
return Platform::SERIAL;
}
/**
* @see Platform#getAutoIncrement()
*/
public function getAutoIncrement()
{
return "";
}
/**
* @see Platform#getMaxColumnNameLength()
*/
public function getMaxColumnNameLength()
{
return 32;
}
/**
* Escape the string for RDBMS.
* @param string $text
* @return string
*/
public function disconnectedEscapeText($text)
{
if (function_exists('pg_escape_string')) {
return pg_escape_string($text);
} else {
return parent::disconnectedEscapeText($text);
}
}
/**
* @see Platform::getBooleanString()
*/
public function getBooleanString($b)
{
// parent method does the checking for allowes tring
// representations & returns integer
$b = parent::getBooleanString($b);
return ($b ? "'t'" : "'f'");
}
/**
* @see Platform::supportsNativeDeleteTrigger()
*/
public function supportsNativeDeleteTrigger()
{
return true;
}
/**
* @see Platform::hasSize(String)
* TODO collect info for all platforms
*/
public function hasSize($sqlType)
{
return !("BYTEA" == $sqlType || "TEXT" == $sqlType);
}
/**
* Whether the underlying PDO driver for this platform returns BLOB columns as streams (instead of strings).
* @return boolean
*/
public function hasStreamBlobImpl()
{
return true;
}
}

Some files were not shown because too many files have changed in this diff Show more