{{Doctrine_Pager_Layout}} does a really good job, but sometimes it is not enough. Let's suppose a situation where you have to create a layout of pagination like this one:

<<  <  1 2 3 4 5  >  >>

Currently, it is impossible with raw {{Doctrine_Pager_Layout}}. But if you extend it and use the available methods, you can achieve it. The base Layout class provides you some methods that can be used to create your own implementation. They are:

<code type="php">
// $this refers to an instance of Doctrine_Pager_Layout

// Defines a mask replacement. When parsing template, it converts replacement
// masks into new ones (or values), allowing to change masks behavior on the fly
$this->addMaskReplacement($oldMask, $newMask, $asValue = false);

// Remove a mask replacement
$this->removeMaskReplacement($oldMask);

// Remove all mask replacements
$this->cleanMaskReplacements();

// Parses the template and returns the string of a processed page
$this->processPage($options = array()); // Needs at least page_number offset in $options array

// Protected methods, although very useful

// Parse the template of a given page and return the processed template
$this->_parseTemplate($options = array());

// Parse the url mask to return the correct template depending of the options sent
// Already process the mask replacements assigned
$this->_parseUrlTemplate($options = array());

// Parse the mask replacements of a given page
$this->_parseReplacementsTemplate($options = array());

// Parse the url mask of a given page and return the processed url
$this->_parseUrl($options = array());

// Parse the mask replacements, changing from to-be replaced mask with new masks/values
$this->_parseMaskReplacements($str);
</code>

Now that you have a small tip of useful methods to be used when extending {{Doctrine_Pager_Layout}}, it's time to see our implemented class:

<code type="php">
class PagerLayoutWithArrows extends Doctrine_Pager_Layout
{
	public function display($options = array(), $return = false)
	{
		$pager = $this->getPager();
		$str = '';

		// First page
		$this->addMaskReplacement('page', '&laquo;', true);
		$options['page_number'] = $pager->getFirstPage();
		$str .= $this->processPage($options);

		// Previous page
		$this->addMaskReplacement('page', '&lsaquo;', true);
		$options['page_number'] = $pager->getPreviousPage();
		$str .= $this->processPage($options);

		// Pages listing
		$this->removeMaskReplacement('page');
		$str .= parent::display($options, true);

		// Next page
		$this->addMaskReplacement('page', '&rsaquo;', true);
		$options['page_number'] = $pager->getNextPage();
		$str .= $this->processPage($options);

		// Last page
		$this->addMaskReplacement('page', '&raquo;', true);
		$options['page_number'] = $pager->getLastPage();
		$str .= $this->processPage($options);

		// Possible wish to return value instead of print it on screen
		if ($return) {
			return $str;
		}

		echo $str;
	}
}
</code>


As you may see, I have to manual process the items <<, <, > and >>. I override the **{%page}** mask by setting a raw value to it (raw value is achieved by setting the third parameter as true). Then I define the only MUST HAVE information to process the page and call it. The return is the template processed as a string. I do it to any of my custom buttons.

Now supposing a totally different situation. Doctrine is framework agnostic, but many of our users use it together with Symfony. {{Doctrine_Pager}} and subclasses are 100% compatible with Symfony, but {{Doctrine_Pager_Layout}} needs some tweaks to get it working with Symfony's {{link_to}} helper function. To allow this usage with {{Doctrine_Pager_Layout}}, you have to extend it and add your custom processor over it. For example purpose (it works in Symfony), I used **{link_to}...{/link_to}** as a template processor to do this job. Here is the extended class and usage in Symfony:

<code type="php">
// CLASS:

class sfDoctrinePagerLayout extends Doctrine_Pager_Layout
{
	public function __construct($pager, $pagerRange, $urlMask)
	{
		sfLoader::loadHelpers(array('Url', 'Tag'));
		parent::__construct($pager, $pagerRange, $urlMask);
	}


	protected function _parseTemplate($options = array())
	{
		$str = parent::_parseTemplate($options);

		return preg_replace(
			'/\{link_to\}(.*?)\{\/link_to\}/', link_to('$1', $this->_parseUrl($options)), $str
		);
	}
}



// USAGE:

$pager_layout = new sfDoctrinePagerLayout(
    $pager,
    new Doctrine_Pager_Range_Sliding(array('chunk' => 5)),
    '@hostHistoryList?page={%page_number}'
);

$pager_layout->setTemplate('[{link_to}{%page}{/link_to}]');
</code>