Skip to content

Commit

Permalink
[1.6] Gave ActriveRecord and PropelCollection objects the ability to …
Browse files Browse the repository at this point in the history
…output YAML when cast as strings (closes #1088)
  • Loading branch information
fzaninotto committed Aug 13, 2010
1 parent 52cea63 commit 76eed92
Show file tree
Hide file tree
Showing 14 changed files with 247 additions and 4 deletions.
66 changes: 66 additions & 0 deletions WHATS_NEW
Expand Up @@ -53,6 +53,72 @@ $book->fromXML($bookString);
echo $book->getTitle(); // Don Juan
}}}

== Model Objects String Representation ==

Taking advantage of the dumping abilities just introduced, all ActiveRecord objects now have a string representation based on a YAML dump of their properties:

{{{
#!php
<?php
$author = new Author();
$author->setFirstName('Leo');
$author->setLastName('Tolstoi');
echo $author;
// Id: null
// FirstName: Leo
// LastName: Tolstoi
// Email: null
// Age: null
}}}

'''Tip''': Tables with a column using the `isPrimaryString` attribute still output the value of a single column as string representation.

`PropelCollection` objects also take advantage from this possibility:

{{{
#!php
<?php
$authors = AuthorQuery::create()
->orderByLastName()
->find();
echo $authors;
// Author_0:
// Id: 456
// FirstName: Jane
// LastName: Austen
// Email: null
// Age: null
// Author_1:
// Id: 147
// FirstName: Leo
// LastName: Tolstoi
// Email: null
// Age: null
}}}

If you want to use another format for the default string representation instead of YAML, you can set the `defaultStringFormat` attribute to any of the supported formats in either the `<database>` or the `<table>` elements in the XML schema:

{{{
#!php
<table name="publisher" defaultStringFormat="XML">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="name" required="true" type="VARCHAR" size="128" />
</table>
}}}

{{{
#!php
<?php
$publisher = new Publisher();
$publisher->setName('Penguin');
echo $publisher;
//<?xml version="1.0" encoding="UTF-8"?>
//<data>
// <Id></Id>
// <Name><![CDATA[Peguin]]></Name>
//</data>
}}}

== Multiple Buildtime Connections ==

Propel 1.5 used the `build.properties` for buildtime connection settings. This had one major drawback: it used to be impossible to deal with several connections at buildtime, let alone several RDBMS.
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/03-Basic-CRUD.txt
Expand Up @@ -45,7 +45,7 @@ The `id` column was set automatically by the database, since the `schema.xml` de

These calls don't issue a database query, since the `Author` object is already loaded in memory.

You can also export all the properties of an object by calling one of the following methods: `toArray()`, `toXML()`, `toYAML()`, `toJSON()`, and `toCSV()`:
You can also export all the properties of an object by calling one of the following methods: `toArray()`, `toXML()`, `toYAML()`, `toJSON()`, `toCSV()`, and `__toString()`:

{{{
#!php
Expand Down
9 changes: 9 additions & 0 deletions docs/reference/ModelCriteria.txt
Expand Up @@ -962,7 +962,16 @@ coll populateRelation($name) // makes an additional query to populate the objec
// Import/Export methods
array toArray() // exports all the objects as array
array toKeyValue($keyColumn, $valueColumn) // exports two columns as a hash
string toXML()
string toYAML()
string toJSON()
string toCSV()
string __toString() // exports to a string using the default string representation (YAML)
void fromArray($array) // imports a collection from an array
void toXML($xml)
void toYAML($yaml)
void toJSON($json)
void toCSV($csv)
}}}

'''Tip''': `PropelCollection` extends `ArrayObject`, so you can also call all the methods of this SPL class on a collection (including `count()`, `append()`, `ksort()`, etc.).
Expand Down
14 changes: 13 additions & 1 deletion generator/lib/builder/om/PHP5ObjectBuilder.php
Expand Up @@ -4213,9 +4213,21 @@ public function __toString()
return (string) \$this->get{$column->getPhpName()}();
}
";
break;
return;
}
}
// no primary string column, falling back to default string format
$script .= "
/**
* Return the string representation of this object
*
* @return string
*/
public function __toString()
{
return (string) \$this->exportTo(" . $this->getPeerClassname() . "::DEFAULT_STRING_FORMAT);
}
";
}

/**
Expand Down
3 changes: 3 additions & 0 deletions generator/lib/builder/om/PHP5PeerBuilder.php
Expand Up @@ -215,6 +215,9 @@ protected function addConstantsAndAttributes(&$script)
$this->addInheritanceColumnConstants($script);

$script .= "
/** The default string format for model objects of the related table **/
const DEFAULT_STRING_FORMAT = '" . $this->getTable()->getDefaultStringFormat() . "';
/**
* An identiy map to hold any loaded instances of ".$this->getObjectClassname()." objects.
* This must be public so that other peer classes can access this when hydrating from JOIN
Expand Down
31 changes: 30 additions & 1 deletion generator/lib/model/Database.php
Expand Up @@ -53,6 +53,14 @@ class Database extends XMLElement
private $heavyIndexing;
protected $tablePrefix = '';

/**
* The default string format for objects based on this database
* (e.g. 'XML', 'YAML', 'CSV', 'JSON')
*
* @var string
*/
protected $defaultStringFormat;

private $domainMap = array();

/**
Expand Down Expand Up @@ -93,6 +101,7 @@ protected function setupObject()
$this->defaultTranslateMethod = $this->getAttribute("defaultTranslateMethod", Validator::TRANSLATE_NONE);
$this->heavyIndexing = $this->booleanValue($this->getAttribute("heavyIndexing"));
$this->tablePrefix = $this->getAttribute('tablePrefix', $this->getBuildProperty('tablePrefix'));
$this->defaultStringFormat = $this->getAttribute('defaultStringFormat', 'YAML');
}

/**
Expand Down Expand Up @@ -250,6 +259,26 @@ public function getDefaultTranslateMethod()
return $this->defaultTranslateMethod;
}

/**
* Set the default string format for ActiveRecord objects in this Db.
*
* @param string $defaultStringFormat Any of 'XML', 'YAML', 'JSON', or 'CSV'
*/
public function setDefaultStringFormat($defaultStringFormat)
{
$this->defaultStringFormat = $defaultStringFormat;
}

/**
* Get the default string format for ActiveRecord objects in this Db.
*
* @return string The default string format
*/
public function getDefaultStringFormat()
{
return $this->defaultStringFormat;
}

/**
* Set the value of defaultTranslateMethod.
* @param string $v The default translate method to use.
Expand All @@ -258,7 +287,7 @@ public function setDefaultTranslateMethod($v)
{
$this->defaultTranslateMethod = $v;
}

/**
* Get the value of heavyIndexing.
*
Expand Down
33 changes: 33 additions & 0 deletions generator/lib/model/Table.php
Expand Up @@ -292,6 +292,14 @@ class Table extends XMLElement implements IDMethod
* @var boolean
*/
protected $isCrossRef = false;

/**
* The default string format for objects based on this table
* (e.g. 'XML', 'YAML', 'CSV', 'JSON')
*
* @var string
*/
protected $defaultStringFormat;

/**
* Constructs a table object with a name
Expand Down Expand Up @@ -345,6 +353,7 @@ public function setupObject()
$this->reloadOnInsert = $this->booleanValue($this->getAttribute("reloadOnInsert"));
$this->reloadOnUpdate = $this->booleanValue($this->getAttribute("reloadOnUpdate"));
$this->isCrossRef = $this->getAttribute("isCrossRef", false);
$this->defaultStringFormat = $this->getAttribute('defaultStringFormat');
}

/**
Expand Down Expand Up @@ -1007,6 +1016,30 @@ public function setNamespace($v)
$this->namespace = $v;
}

/**
* Set the default string format for ActiveRecord objects in this Table.
*
* @param string $defaultStringFormat Any of 'XML', 'YAML', 'JSON', or 'CSV'
*/
public function setDefaultStringFormat($defaultStringFormat)
{
$this->defaultStringFormat = $defaultStringFormat;
}

/**
* Get the default string format for ActiveRecord objects in this Table,
* or the one for the whole database if not set.
*
* @return string The default string representation
*/
public function getDefaultStringFormat()
{
if (!$this->defaultStringFormat && $this->getDatabase() && $this->getDatabase()->getDefaultStringFormat()) {
return $this->getDatabase()->getDefaultStringFormat();
}
return $this->defaultStringFormat;
}

/**
* Get the method for generating pk's
* [HL] changing behavior so that Database default method is returned
Expand Down
2 changes: 2 additions & 0 deletions generator/resources/dtd/database.dtd
Expand Up @@ -33,6 +33,7 @@ PHP class or method name.
defaultPhpNamingMethod (nochange|underscore|phpname) "underscore"
heavyIndexing (true|false) "false"
tablePrefix CDATA #IMPLIED
defaultStringFormat CDATA #IMPLIED
>

<!ELEMENT external-schema EMPTY>
Expand Down Expand Up @@ -63,6 +64,7 @@ PHP class or method name.
phpNamingMethod (nochange|underscore|phpname) #IMPLIED
heavyIndexing (true|false) #IMPLIED
description CDATA #IMPLIED
defaultStringFormat CDATA #IMPLIED
>

<!ELEMENT id-method-parameter EMPTY>
Expand Down
14 changes: 14 additions & 0 deletions generator/resources/xsd/database.xsd
Expand Up @@ -754,6 +754,13 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="defaultStringFormat" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">
The default format used to convert objects based on this table to strings. Propel supports by default the 'XML', 'YAML', 'JSON', and 'CSV' formats, but custom formats are also possible.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>

<xs:complexType name="database">
Expand Down Expand Up @@ -858,5 +865,12 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="defaultStringFormat" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en">
The default format used to convert objects based on this database to strings. Propel supports by default the 'XML', 'YAML', 'JSON', and 'CSV' formats, but custom formats are also possible.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:schema>
10 changes: 10 additions & 0 deletions runtime/lib/collection/PropelCollection.php
Expand Up @@ -470,5 +470,15 @@ public function __call($name, $params)
}
throw new PropelException('Call to undefined method: ' . $name);
}

/**
* Returns a string representation of the current collection.
* Based on the string representation of the underlying objects, defined in
* the Peer::DEFAULT_STRING_FORMAT constant
*/
public function __toString()
{
return (string) $this->exportTo(constant($this->getPeerClass() . '::DEFAULT_STRING_FORMAT'));
}

}
2 changes: 1 addition & 1 deletion test/fixtures/bookstore/schema.xml
Expand Up @@ -26,7 +26,7 @@
</validator>
</table>

<table name="publisher" description="Publisher Table">
<table name="publisher" description="Publisher Table" defaultStringFormat="XML">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" description="Publisher Id" />
<column name="name" required="true" type="VARCHAR" size="128" default="Penguin" description="Publisher Name" />
</table>
Expand Down
7 changes: 7 additions & 0 deletions test/testsuite/generator/builder/om/GeneratedPeerTest.php
Expand Up @@ -86,5 +86,12 @@ public function testAddSelectColumnsAliasLazyLoad()
);
$this->assertEquals($expected, $c->getSelectColumns(), 'addSelectColumns() does not add lazy loaded columns but uses the second parameter as an alias');
}

public function testDefaultStringFormatConstant()
{
$this->assertTrue(defined('BookPeer::DEFAULT_STRING_FORMAT'), 'every Peer class has the DEFAULT_STRING_FORMAT constant');
$this->assertEquals('YAML', AuthorPeer::DEFAULT_STRING_FORMAT, 'default string format is YAML by default');
$this->assertEquals('XML', PublisherPeer::DEFAULT_STRING_FORMAT, 'default string format can be customized using the defaultStringFormat attribute in the schema');
}

}
29 changes: 29 additions & 0 deletions test/testsuite/generator/builder/om/OMBuilderTest.php
Expand Up @@ -71,6 +71,35 @@ public function testClear()
$b->clear();
$this->assertFalse($b->isDeleted(), 'clear() sets the object to not deleted');
}

public function testToStringUsesDefaultStringFormat()
{
$author = new Author();
$author->setFirstName('John');
$author->setLastName('Doe');
$expected = <<<EOF
Id: null
FirstName: John
LastName: Doe
Email: null
Age: null
EOF;
$this->assertEquals($expected, (string) $author, 'generated __toString() uses default string format and exportTo()');

$publisher = new Publisher();
$publisher->setId(345345);
$publisher->setName('Peguinoo');
$expected = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<data>
<Id>345345</Id>
<Name><![CDATA[Peguinoo]]></Name>
</data>
EOF;
$this->assertEquals($expected, (string) $publisher, 'generated __toString() uses default string format and exportTo()');
}
}

class TestableOMBuilder extends OMBuilder
Expand Down
29 changes: 29 additions & 0 deletions test/testsuite/runtime/collection/PropelCollectionConvertTest.php
Expand Up @@ -201,5 +201,34 @@ public function testfromCSV($expected)

$this->assertEquals($this->coll, $coll);
}

/**
* @dataProvider toYamlDataProvider
*/
public function testToStringUsesDefaultStringFormat($expected)
{
$this->assertEquals($expected, (string) $this->coll, 'PropelCollection::__toString() uses the YAML representation by default');
}

public function testToStringUsesCustomStringFormat()
{
$coll = new PropelObjectCollection();
$coll->setModel('Publisher');
$publisher = new Publisher();
$publisher->setId(12345);
$publisher->setName('Penguinoo');
$coll[]= $publisher;
$expected = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<data>
<Publisher>
<Id>12345</Id>
<Name><![CDATA[Penguinoo]]></Name>
</Publisher>
</data>
EOF;
$this->assertEquals($expected, (string) $coll);
}

}

0 comments on commit 76eed92

Please sign in to comment.