Working with Advanced Column Types
Propel offers a set of advanced column types. The database-agnostic implementation allows these types to work on all supported RDBMS.
blob
Columns
Propel uses PHP streams internally for storing Binary Locator Objects (BLOBs). This choice was made because PDO itself uses streams as a convention when returning LOB columns in a resultset and when binding values to prepared statements. Unfortunately, not all PDO drivers support this (see, for example, http://bugs.php.net/bug.php?id=40913); in those cases, Propel creates a php://temp
stream to hold the LOB contents and thus provide a consistent API.
Note that CLOB (Character Locator Objects) are treated as strings in Propel, as there is no convention for them to be treated as streams by PDO.
Getting blob
Values
BLOB values will be returned as PHP stream resources from the accessor methods. Alternatively, if the value is NULL in the database, then the accessors will return the PHP value NULL.
<?php
$media = MediaQuery::create()->findPk(1);
$fp = $media->getCoverImage();
if ($fp !== null) {
echo stream_get_contents($fp);
}
Setting blob
Values
When setting a blob column, you can either pass in a stream or the blob contents.
<?php
// Setting using a stream
$fp = fopen("/path/to/file.ext", "rb");
$media = new Media();
$media->setCoverImage($fp);
// Setting using file contents
$media = new Media();
$media->setCoverImage(file_get_contents("/path/to/file.ext"));
Regardless of which setting method you choose, the blob will always be represented internally as a stream resource – and subsequent calls to the accessor methods will return a stream.
For example:
<?php
$media = new Media();
$media->setCoverImage(file_get_contents("/path/to/file.ext"));
$fp = $media->getCoverImage();
print gettype($fp); // "resource"
Setting blob
columns and isModified()
Note that because a stream contents may be externally modified, mutator methods for blob columns will always set the _isModified() to report true_ – even if the stream has the same identity as the stream that was returned.
For example:
<?php
$media = MediaQuery::create()->findPk(1);
$fp = $media->getCoverImage();
$media->setCoverImage($fp);
var_export($media->isModified()); // TRUE
enum
Columns
Although stored in the database as integers, enum columns let users manipulate a set of predefined values, without worrying about their storage.
<table name="book">
...
<column name="style" type="enum" valueSet="novel, essay, poetry" />
</table>
<?php
// The ActiveRecord setter and getter let users use any value from the valueSet
$book = new Book();
$book->setStyle('novel');
echo $book->getStyle(); // novel
// Trying to set a value not in the valueSet throws an exception
// Enum columns are also searchable, using the generated filterByXXX() method
// or other ModelCriteria methods (like where(), condition())
$books = BookQuery::create()
->filterByStyle('novel')
->find();
object
Columns
Propel offers an object
column type to store PHP objects in the database. The column setter serializes the object, which is later stored to the database as a string. The column getter unserializes the string and returns the object. Therefore, for the end user, the column contains an object.
Getting and Setting object
Values
<?php
class GeographicCoordinates
{
public $latitude, $longitude;
public function __construct($latitude, $longitude)
{
$this->latitude = $latitude;
$this->longitude = $longitude;
}
public function isInNorthernHemisphere()
{
return $this->latitude > 0;
}
}
// The 'house' table has a 'coordinates' column of type object
$house = new House();
$house->setCoordinates(new GeographicCoordinates(48.8527, 2.3510));
echo $house->getCoordinates()->isInNorthernHemisphere(); // true
$house->save();
Retrieving Records based on object
Values
Not only do object
columns benefit from these smart getter and setter in the generated Active Record class, they are also searchable using the generated filterByXXX()
method in the query class:
<?php
$house = HouseQuery::create()
->filterByCoordinates(new GeographicCoordinates(48.8527, 2.3510))
->find();
Propel looks in the database for a serialized version of the object passed as parameter of the filterByXXX()
method.
array
Columns
An array
column can store a simple PHP array in the database (nested arrays and associative arrays are not accepted). The column setter serializes the array, which is later stored to the database as a string. The column getter unserializes the string and returns the array. Therefore, for the end user, the column contains an array.
Getting and Setting array
Values
<?php
// The 'book' table has a 'tags' column of type array
$book = new Book();
$book->setTags(array('novel', 'russian'));
print_r($book->getTags()); // array('novel', 'russian')
// If the column name is plural, Propel also generates hasXXX(), addXXX(),
// and removeXXX() methods, where XXX is the singular column name
echo $book->hasTag('novel'); // true
$book->addTag('romantic');
print_r($book->getTags()); // array('novel', 'russian', 'romantic')
$book->removeTag('russian');
print_r($book->getTags()); // array('novel', 'romantic')
Retrieving Records based on array
Values
Propel doesn’t use serialize()
to transform the array into a string. Instead, it uses a special serialization function, that makes it possible to search for values of array
columns.
<?php
// Search books that contain all the specified tags
$books = BookQuery::create()
->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_ALL)
->find();
// Search books that contain at least one of the specified tags
$books = BookQuery::create()
->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_SOME)
->find();
// Search books that don't contain any of the specified tags
$books = BookQuery::create()
->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_NONE)
->find();
// If the column name is plural, Propel also generates singular filter methods
// expecting a scalar parameter instead of an array
$books = BookQuery::create()
->filterByTag('russian')
->find();
TipFilters on array columns translate to SQL as LIKE conditions. That means that the resulting query often requires a full table scan, and is not suited for large tables.
Warning: Only generated Query classes (through generated filterByXXX()
methods) and ModelCriteria
(through where()
, and condition()
) allow conditions on enum
, object
, and array
columns. Criteria
alone (through add()
, addAnd()
, and addOr()
) does not support conditions on such columns.