1. Overview
      1. What It Is
      2. Why I Would Want to Use It
      3. Known Issues
    2. Getting Started
      1. Fundamentals
        1. Design Patterns
        2. xPDO, the Class
          1. As Object and Relational Mapper
          2. As PDO Wrapper
          3. As Service Layer
          4. The xPDO Constructor
            1. Hydrating Fields
      2. Introduction to the xPDO Object Model
        1. Understanding xPDOCriteria and xPDOQuery
      3. Creating a Model With xPDO
        1. Defining a Schema
          1. Defining Relationships
          2. Defining the Database and Tables
            1. Upgrading Models to Schema Version 1.1
          3. More Examples of xPDO XML Schema Files
          4. Validation Rules in your Schema
        2. Generating the Model Code
          1. Domain Classes
          2. O-R Maps
          3. Table Classes
      4. Using Your xPDO Model
        1. Creating Objects
        2. Database Connections and xPDO
        3. Loading Packages
        4. Removing Objects
          1. removeCollection
        5. Retrieving Objects
          1. getCollectionGraph
        6. Setting Object Fields
        7. Working with Related Objects
    3. Extending Your xPDO Model
      1. Overriding Derived Behavior
        1. Using Custom Object Loaders
      2. Working With Transient Object Classes
    4. Advanced Features
      1. Caching
        1. Caching Tutorial - Basic Snippets
        2. Caching Tutorial - Lifetimes
      2. Object Validation
        1. xPDOForeignKeyConstraint
        2. xPDOMaxLengthValidationRule
        3. xPDOMaxValueValidationRule
        4. xPDOMinLengthValidationRule
        5. xPDOMinValueValidationRule
        6. xPDOObjectExistsValidationRule
    5. xPDO Development
      1. Testing
      2. Building
      3. Documentation and Tutorials
    6. Class Reference
      1. xPDO
        1. xPDO.addPackage
        2. xPDO.beginTransaction
        3. xPDO.commit
        4. xPDO.connect
        5. xPDO.fromJSON
        6. xPDO.getCollection
        7. xPDO.getCollectionGraph
        8. xPDO.getCount
        9. xPDO.getDebug
        10. xPDO.getFields
        11. xPDO.getIterator
        12. xPDO.getManager
        13. xPDO.getObject
        14. xPDO.getObjectGraph
        15. xPDO.getOption
        16. xPDO.getTableName
        17. xPDO.loadClass
        18. xPDO.log
        19. xPDO.newObject
        20. xPDO.newQuery
        21. xPDO.query
        22. xPDO.setDebug
        23. xPDO.setLogLevel
        24. xPDO.setLogTarget
        25. xPDO.setOption
        26. xPDO.toJSON
      2. xPDOCacheManager
        1. xPDOCacheManager.copyFile
        2. xPDOCacheManager.copyTree
        3. xPDOCacheManager.delete
        4. xPDOCacheManager.deleteTree
        5. xPDOCacheManager.endsWith
        6. xPDOCacheManager.escapeSingleQuotes
        7. xPDOCacheManager.get
        8. xPDOCacheManager.getCachePath
        9. xPDOCacheManager.getCacheProvider
        10. xPDOCacheManager.matches
        11. xPDOCacheManager.replace
        12. xPDOCacheManager.set
        13. xPDOCacheManager.writeFile
        14. xPDOCacheManager.writeTree
      3. xPDOGenerator
        1. xPDOGenerator.parseSchema
        2. xPDOGenerator.writeSchema
      4. xPDOManager
        1. xPDOManager.createObjectContainer
        2. xPDOManager.createSourceContainer
        3. xPDOManager.removeObjectContainer
        4. xPDOManager.removeSourceContainer
      5. xPDOObject
        1. Configuration Accessors
          1. getOption
          2. setOption
        2. Field Accessors
          1. fromArray
          2. fromJSON
          3. get
          4. set
          5. toArray
          6. toJSON
        3. Metadata Accessors
          1. getFieldName
          2. getFKClass
          3. getFKDefinition
          4. getPK
          5. getPKType
          6. getSelectColumns
        4. Persistence Methods
          1. remove
          2. save
        5. Related Object Accessors
          1. addMany
          2. addOne
          3. getMany
          4. getOne
        6. State Accessors
          1. isDirty
          2. isLazy
          3. isNew
        7. Static Object Loaders
          1. _loadCollectionInstance
          2. _loadInstance
          3. _loadRows
          4. load
          5. loadCollection
          6. loadCollectionGraph
          7. Using Custom Loader Classes
        8. Validation
          1. addValidationRule
          2. getValidator
          3. isValidated
          4. removeValidationRules
          5. validate
      6. xPDOQuery
        1. xPDOQuery.andCondition
        2. xPDOQuery.groupby
        3. xPDOQuery.innerJoin
        4. xPDOQuery.leftJoin
        5. xPDOQuery.limit
        6. xPDOQuery.orCondition
        7. xPDOQuery.rightJoin
        8. xPDOQuery.select
        9. xPDOQuery.setClassAlias
        10. xPDOQuery.sortby
        11. xPDOQuery.where
      7. xPDORevisionControl
      8. xPDOTransport
        1. xPDOTransport.install
        2. xPDOTransport.pack
        3. xPDOTransport.uninstall
      9. xPDOValidator
        1. xPDOValidator.addMessage
        2. xPDOValidator.getMessages
        3. xPDOValidator.hasMessages
        4. xPDOValidator.validate

Defining the Database and Tables

Last edited by Everett Griffiths on Nov 7, 2013.

Let's say we have a Package called 'Storefinder'. We want to create a custom schema for that package. First off, we'll create a schema file with this name:


If you note, we added in the 'mysql' postfix to the filename, since xPDO will eventually allow for multiple database development. We want to specify that this schema is for a MySQL table.

Starting with a Database

Our current XML file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<model package="storefinder" 

First we'll tell the browser and parser that this is XML code with a standard XML header. Next, we're going to create a "model" tag, and put some attributes into it. The "model" tag is a representation of the database itself. The attributes are:

  • package - The name of the xPDO package (note this is different than a "transport package", a Revolution term). This is how xPDO separates different models and manages them. Note: in the XML, the package name must be all lowercase.
  • baseClass - This is the base class from which all your class definitions will extend. Unless you're planning on creating a custom xPDOObject extension, it's best to leave it at the default.
  • platform — The database platform PDO driver you are using. At this time, xPDO supports mysql, sqlite, and sqlsrv PDO drivers.
  • defaultEngine — The default engine of the database tables, usually either MyISAM or InnoDB. xPDO recommends using MyISAM.
  • tablePrefix — An optional parameter that can be set to override the default runtime table prefix. Useful for creating 3rd party components.
  • phpdoc-package & phpdoc-subpackage — These are custom attributes we're going to use in our map and class files. They're not standard xPDO attributes, but show that you can put whatever you want as attributes.
  • version — The version of the xPDO schema. As changes are made to the schema format, the version is updated to differentiate how the model is handled at runtime.
Schema Version 1.1
In 2.0.0-rc3, the schema was changed to implement a new model element that describes Table Indexes separately from the field element's index and index_group attributes. See Upgrading Models to Schema Version 1.1 for information on migrating your index definitions to the new format. Do not add version="1.1" (leave off the version attribute or set it to 1.0) if you have not yet described your indexes in the new schema format or xPDO will create the tables with no indexes.

Defining Tables

Great! Now we've got our model definition. Let's add a table tag as the next line.

<object class="sfStore" table="stores" extends="xPDOSimpleObject">

"Object" is our representation of a table, which will generate into an xPDOObject class when we're through. There are some attributes to note here:

  • class — This is the name of the class we want to be generated from the table. Here, we'll use "sfStore". Note that instead of just "Store", we prefixed it with "sf" to prevent collisions with any other packages we might install that might also have Store tables.
  • table — This should point to the actual database table name, minus the tablePrefix we specified for the package.
  • extends — This is the class that it extends. Note that you can make subclasses and extended classes straight from the XML. Extended classes will inherit their parent class's fields.

You'll see here that this table extends "xPDOSimpleObject", rather than xPDOObject. This means that the table comes already with an "id" field, that is an auto-increment primary key.

Now that we've got a table definition for our stores table, let's add some field definitions to it:

<field key="name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
<field key="address" dbtype="varchar" precision="255" phptype="string" null="false" default="" />
<field key="city" dbtype="varchar" precision="255" phptype="string" null="false" default="" />
<field key="state" dbtype="varchar" precision="255" phptype="string" null="false" default="" />
<field key="zip" dbtype="varchar" precision="10" phptype="string" null="false" default="0" index="index" />
<field key="country" dbtype="varchar" precision="20" phptype="string" null="false" default="" />
<field key="phone" dbtype="varchar" precision="20" phptype="string" null="false" default="" />
<field key="fax" dbtype="varchar" precision="20" phptype="string" null="false" default="" />
<field key="active" dbtype="int" precision="1" attributes="unsigned" phptype="integer" null="false" default="0" />

As you can see here, each column in our table has a field definition tag. From there, we have attribute properties for each field. Most of these are optional, depending on the database type of the column. Some of those attribute properties are:

  • key — The key name of the column.
  • dbtype — The DB type - such as varchar, int, text, tinyint, etc.
  • precision — The precision of the field. Usually this is the max number of characters.
  • attributes — Only applies to some DB types; in integers you can set to "unsigned" to make sure that the value is always positive.
  • phptype — The corresponding PHP type of the DB field type.
  • null — If the field can be NULL or not.
  • default — The default starting value of the field should none be set.
  • index (deprecated) — An optional field, when set, will add a type of index to the field. Some of the values are "pk", "index", and "fk".
index is deprecated
The index attribute is deprecated for Schema Version 1.1 and ignored when you generate your models as version 1.1. This is only valid for models with no version attribute (or the version set explicitly to 1.0).

Next, we'll define the indexes we want our table to have:

<index alias="name" name="name" primary="false" unique="false" type="BTREE">
    <column key="name" length="" collation="A" null="false" />
<index alias="zip" name="zip" primary="false" unique="false" type="BTREE">
    <column key="zip" length="" collation="A" null="false" />
The alias element
New in xPDO 2.2 is the ability to define field aliases. This can be useful when changing table structures to maintain backwards compatibility, or for defining useful aliases for the object API without having to modify table structure. The syntax is simple with two attributes, key (the alias) and field (the target field definition).

Now let's define an alias for the zip column called postalcode so the value can be accessed by either key:

<alias key="postalcode" field="zip" />

And finally, we'll finish the table definition by closing the object tag:


Now let's add an "sfOwner" class, which will represent any owners we have:

<object class="sfOwner" table="owners" extends="xPDOSimpleObject">
  <field key="name" dbtype="varchar" precision="100" phptype="string" null="false" default="" index="index" />
  <field key="email" dbtype="varchar" precision="255" phptype="string" null="false" default="" />

  <index alias="name" name="name" primary="false" unique="false" type="BTREE">
      <column key="name" length="" collation="A" null="false" />

And since we want our stores to possibly have multiple owners, let's add a sfStoreOwner class, that will bridge the many-to-many relationship:

<object class="sfStoreOwner" table="store_owners" extends="xPDOSimpleObject">
  <field key="store" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />
  <field key="owner" dbtype="int" precision="10" attributes="unsigned" phptype="integer" null="false" default="0" index="index" />

  <index alias="store" name="store" primary="false" unique="false" type="BTREE">
      <column key="store" length="" collation="A" null="false" />
  <index alias="owner" name="owner" primary="false" unique="false" type="BTREE">
      <column key="owner" length="" collation="A" null="false" />

Let's close the model definition:


We have a completed XML schema for our model. Now we'll need to define relationships for that schema.

Suggest an edit to this page on GitHub (Requires GitHub account. Opens a new window/tab) or become an editor of the MODX Documentation.