<?php
/**
* LICENSE
*
* This source file is subject to the new BSD license
* It is available through the world-wide-web at this URL:
* http://www.petala-azul.com/bsd.txt
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to geral@petala-azul.com so we can send you a copy immediately.
*
* @package Bvb_Grid
* @author Bento Vilas Boas <geral@petala-azul.com>
* @copyright 2010 ZFDatagrid
* @license http://www.petala-azul.com/bsd.txt New BSD License
* @version $Id$
* @link http://zfdatagrid.com
*/
/**
*
* This class will abstract results from a data source for descendants
*
*
* @package Bvb_Grid
* @author Bento Vilas Boas <geral@petala-azul.com>
* @copyright 2010 ZFDatagrid
* @license http://www.petala-azul.com/bsd.txt New BSD License
* @version Release: @package_version@
* @category Bvb_Grid
*/
abstract class Bvb_Grid {
/**
* Current Revision
* @var string
*/
const VERSION = '$Rev$';
/**
* If we should use mod_write for URL's
*
* @var bool
* @static
*/
protected static $_modRewrite = false;
/**
* Default Configuration to be applied to all grids
*
* @var array
* @static
*/
protected static $_defaultConfig = array();
/**
* Location for deploy class
*
* @var mixed
*/
protected static $_deployClassesDir = false;
/**
* Char encoding
*
* @var string
*/
protected $_charEncoding = 'UTF-8';
/**
* Fields order
*
* @var array
*/
private $_fieldsOrder;
/**
* The path where we can find the library
* Usually is lib or library
*
* @var string
*/
protected $_libraryDir = 'library';
/**
* templates type to be used
*
* @var array
*/
protected $_templates;
/**
* dir and prefix list to be used when formatting fields
*
*/
protected $_formatter;
/**
* Number of results per page
*
* @var int
*/
protected $_recordsPerPage = 15;
/**
* Number of results to per page
*
* @var array
*/
protected $_paginationInterval = array();
/**
* Type of export available
*
* @var array
*/
protected $_export = array('pdf',
'word',
'wordx',
'excel',
'print',
'xml',
'csv',
'ods',
'odt',
'json');
/**
* All info that is not directly related to the database
*/
protected $_info = array();
/**
* URL to prefix in case of routes
*
* @var bool
*/
protected $_routeName = null;
/**
* Baseurl
*
* @var string
*/
protected $_baseUrl;
/**
* Array containing the query result from table(s)
*
* @var array
*/
protected $_result;
/**
* Total records from db query
*
* @var int
*/
protected $_totalRecords;
/**
* Array containing field titles
*
* @var array
*/
protected $_titles;
/**
* Array containing table(s) fields
*
* @var array
*/
protected $_fields = array();
/**
* Filters list
*
* @var array
*/
protected $_filters = array();
/**
* Filters Render
* @var
*/
protected $_filtersRenders;
/**
* External fielters to be applied
*
* @var array
*/
protected $_externalFilters = array();
/**
* Extra Rows
*
* @var array
*/
protected $_extraRows = array();
/**
* Filters values inserted by the user
*
* @var array
*/
protected $_filtersValues;
/**
* All information database related
*
* @var array
*/
protected $_data = array();
/**
* URL params
*
* @var string
*/
protected $_ctrlParams = array();
/**
* Extra Columns array
*
* @var array
*/
protected $_extraColumns = array();
/**
* Final fields list (after all procedures).
*
* @var array
*/
protected $_finalFields;
/**
* Use cache or not.
* @var bool
*/
protected $_cache = false;
/**
* Template instance
*
* @var object
*/
protected $_temp;
/**
* Check if all columns have been added by ->query()
*
* @var bool
*/
private $_allFieldsAdded = false;
/**
* Default filters to be applied
*
* @var array
* @return array
*/
protected $_defaultFilters;
/**
* Instead throwing an exception,
* we queue the field list and call this in
* getFieldsFromQuery()
*
* @var array
*/
protected $_updateColumnQueue = array();
/**
* List of callback functions to apply
* on grid deploy and ajax
*
* @var array
*/
protected $_configCallbacks = array();
/**
* Treat hidden fields as 'remove'
*
* @var bool
*/
protected $_removeHiddenFields = false;
/**
* Functions to be applied on every fields before display
*
* @var string
*/
protected $_escapeFunction = 'htmlspecialchars';
/**
* Grid Options.
*
* @var array
*/
protected $_options = array();
/**
* Id used for multiples instances on the same page
*
* @var string
*/
protected $_gridId;
/**
* Colspan for table
*
* @var int
*/
protected $_colspan;
/**
* User defined INFO for templates
*
* @var array
*/
protected $_templateParams = array();
/**
* Array of fields that should appear on detail view
*
* @var array
*/
protected $_gridColumns = null;
/**
* Array of columns that should appear on detail view
*
* @var array
*/
protected $_detailColumns = null;
/**
* If we are on detail or grid view
*
* @var bool
*/
protected $_isDetail = false;
/**
* @var Zend_View_Interface
*/
protected $_view;
/**
* Information from FORM
*
* @var object
*/
protected $_crud = null;
/**
*
* @var Bvb_Grid_Source_SourceInterface
*/
private $_source = null;
/**
* Last name from deploy class (table|pdf|csv|etc...)
*
* @var string
*/
protected $_deployName = null;
/**
* What is being done with this request
*
* @var array
*/
protected $_willShow = array();
/**
* Print class based on conditions
*
* @var array
*/
protected $_classRowCondition = array();
/**
* Result to apply to every <tr> based on condition
*
* @var $_classRowConditionResult array
*/
protected $_classRowConditionResult = array();
/**
* CSS classes to be used
*
* @var array
*/
protected $_cssClasses = array('odd' => 'alt', 'even' => '');
/**
* Condition to apply a CSS class to a table cell <td>
*
* @var array
*/
protected $_classCellCondition = array();
/**
* Order setted by adapter
*
* @var string
*/
protected $_order;
/**
* custom translate instance
*
* @var Zend_Translate
*/
protected $_translator;
/**
* If filters by user will be showed when exporting
*
* @var bool
*/
protected $_showFiltersInExport = false;
/**
* If whe should save filters in session
*
* @var bool
*/
protected $_paramsInSession = false;
/**
* Session Params Zend_Session
*
* @var array
*/
protected $_sessionParams = false;
/**
* Hold definitions from configurations
*
* @var array
*/
protected $_deploy = array();
/**
* Contains URL's for edit and delete records
* Can be called from a decorator using
* {{detailUrl}}
* {{deleteUrl}}
* {{editUrl}}
* {{addUrl}}
*
* @var array
*/
protected $_actionsUrls = array('add' => '',
'edit' => '',
'delete' => '',
'detail' => '');
/**
* Permission to add records
*
* @var bool
*/
protected $_allowAdd = false;
/**
* Options for adition
*
* @var array
*/
protected $_allowAddButton = array();
/**
* Permission to edit records
*
* @var bool
*/
protected $_allowEdit = false;
/**
* Permission to delete records
*
* @var bool
*/
protected $_allowDelete = false;
/**
* Makes shure that config callbacks will be used once
*
* @var boolean
*/
protected $_runCallbacks = true;
/**
* Events manager class
*
* @var Bvb_Grid_Event_Dispatcher
*/
protected $_eventDispatcher = false;
/**
* Request Instance
*
* @var Zend_Controller_Request_Abstract
*/
protected $_request = null;
/**
* Response Instance
*
* @var Zend_Controller_Response_Abstract
*/
protected $_response = null;
/**
*
* @var Zend_Controller_Front
*/
protected $_controller = null;
/**
* Mass Actions instance holder
*
* @var Bvb_Grid_Mass_Actions
*/
protected $_massActions = null;
/**
* Event prefix for the current instance
*
* @var string/null
*/
protected $_eventsPrefix = null;
/**
* The __construct function receives the db adapter. All information related to the
* URL is also processed here
*
* @param array $options An Array or Zend_Config object.
*
* @return void
*/
public function __construct($options)
{
if (!$this instanceof Bvb_Grid_Deploy_DeployInterface) {
throw new Bvb_Grid_Exception(get_class($this) . ' needs to implement Bvb_Grid_Deploy_DeployInterface');
}
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} else if (!is_array($options)) {
throw new Bvb_Grid_Exception('options must be an instance from Zend_Config or an array');
}
$this->_options = array_merge_recursive(self::getDefaultConfig(), $options);
// get the controller params and baseurl to use with filters
if (isset($this->_options['grid']['requestParams'])) {
// use from configuration, remove it from _options to enforce correct usage
$this->setParams($this->_options['grid']['requestParams']);
unset($this->_options['grid']['requestParams']);
} else {
// use the request parameters
$this->setParams($this->getRequest()->getParams());
}
if (isset($this->_options['grid']['baseUrl'])) {
// use from configuration, remove it from _options to enforce correct usage
$this->_baseUrl = $this->_options['grid']['baseUrl'];
unset($this->_options['grid']['baseUrl']);
} else {
// use controllers value
$this->_baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl();
}
foreach (array('massActionsAll_', 'gridAction_', 'send_') as $value) {
$this->clearParam($value);
}
foreach ($this->_ctrlParams as $key => $value) {
if (is_array($value)) {
$this->clearParam($key);
}
}
/**
* plugins loaders
*/
$this->_formatter = new Zend_Loader_PluginLoader();
//Templates loading
if (is_array($this->_export)) {
foreach ($this->_export as $key => $temp) {
if (is_array($temp)) {
$export = $key;
} else {
$export = $temp;
}
$this->_templates[$export] = new Zend_Loader_PluginLoader(array());
}
}
// Add the formatter fir for fields content
$this->addFormatterDir('Bvb/Grid/Formatter', 'Bvb_Grid_Formatter');
$deploy = explode('_', get_class($this));
$this->_deployName = strtolower(end($deploy));
$renderDir = ucfirst($this->_deployName);
$this->_filtersRenders = new Zend_Loader_PluginLoader();
$this->addFiltersRenderDir('Bvb/Grid/Filters/Render/' . $renderDir, 'Bvb_Grid_Filters_Render_' . $renderDir);
if (!defined('E_USER_DEPRECATED')) {
define('E_USER_DEPRECATED', E_USER_WARNING);
}
$this->_sessionParams = new Zend_Session_Namespace('ZFDG_FILTERS' . $this->getGridId(true));
//Set an empty event dispatcher
$this->setEventDispatcher(Bvb_Grid_Event_Dispatcher::getInstance());
//set an empty mass action
$this->setMassActions(new Bvb_Grid_Mass_Actions());
}
/**
* Defines controller
*
* @param Zend_Controller_Front $controller
* @return Bvb_Grid
*/
public function setController(Zend_Controller_Front $controller)
{
$this->_controller = $controller;
return $this;
}
/**
* Returns current controller instance
*
* @return Zend_Contrller_Front
*/
public function getController()
{
if (is_null($this->_controller)) {
$this->_controller = Zend_Controller_Front::getInstance();
}
return $this->_controller;
}
/**
* Backwards compatibility
*
* @param mixed $object A Zend_Db object
*
* @return Bvb_Grid
* @deprecated Use setSource()
*/
public function query($object)
{
if ($object instanceof Zend_Db_Select) {
$this->setSource(new Bvb_Grid_Source_Zend_Select($object));
} elseif ($object instanceof Zend_Db_Table_Abstract) {
$this->setSource(new Bvb_Grid_Source_Zend_Table($object));
} else {
throw new Bvb_Grid_Exception('Please use setSource() method instead');
}
return $this;
}
/**
* Sets the source to be used
*
* Bvb_Grid_Source_*
*
* @param Bvb_Grid_Source_SourceInterface $source A valid interface
*
* @return Bvb_Grid
*/
public function setSource(Bvb_Grid_Source_SourceInterface $source)
{
if ($this->getSource()) {
throw new Bvb_Grid_Exception('You can not set source twice');
}
$this->_source = $source;
$this->emitEvent('grid.set_source', array('source' => $this->getSource()));
$this->getSource()->setCache($this->getCache());
$tables = $this->getSource()->getMainTable();
$this->_data['table'] = $tables['table'];
if (isset($tables['schema']))
$this->_data['schema'] = $tables['schema'];
$this->_crudTable = $this->_data['table'];
$fields = $this->getSource()->buildFields();
foreach ($fields as $key => $field) {
$this->updateColumn($key, $field);
}
$this->_allFieldsAdded = true;
$this->emitEvent('grid.all_fields_added', array('fields' => &$this->_data['fields']));
//Apply options to the fields
$this->_applyOptionsToFields();
return $this;
}
/**
* The path where we can find the library
* Usually is lib or library
*
* @param string $dir Zend Lib location
*
* @return Bvb_Grid
*/
public function setLibraryDir($dir)
{
$this->_libraryDir = $dir;
return $this;
}
/**
* Returns the actual library path
*
* @return string
*/
public function getLibraryDir()
{
return $this->_libraryDir;
}
/**
* Sets grid cache
*
* @param mixed $cache Cache arguments
*
* @return mixed
*/
public function setCache($cache)
{
if ($cache == false || (is_array($cache) && isset($cache['enable']) && $cache['enable'] == 0)) {
$this->_cache = array('enable' => 0);
return $this;
}
if (is_array($cache) && isset($cache['enable']) && isset($cache['instance']) && isset($cache['tag'])) {
$this->_cache = $cache;
if ($this->getSource() !== null) {
$this->getSource()->setCache($this->getCache());
}
return $this;
}
return false;
}
/**
* Returns actual cache params
*
* @return Zend_Cache
*/
public function getCache()
{
return $this->_cache;
}
/**
* Returns the actual source object
*
* @return Bvb_Grid_Source_SourceInterface
*/
public function getSource()
{
return $this->_source;
}
/**
* Defines a custom Translator
*
* @param Zend_Translate $translator Translator instance to be used
*
* @return Bvb_Grid
*/
public function setTranslator(Zend_Translate $translator)
{
Bvb_Grid_Translator::getInstance()->setTranslator($translator);
return $this;
}
/**
* Returns current request from Zend_Controller_Front
*
* @return Zend_Controller_Front::getInstance()->getReguest();
*/
public function getRequest()
{
if (!$this->_request) {
$this->_request = $this->getController()->getRequest();
}
return $this->_request;
}
/**
* Defines request instance
*
* @param Zend_Controller_Request_Abstract $request
* @return Bvb_Grid
*/
public function setRequest(Zend_Controller_Request_Abstract $request)
{
$this->_request = $request;
return $this;
}
/**
* Set view object
*
* @param Zend_View_Interface $view view object to use
*
* @return Bvb_Grid
*/
public function setView(Zend_View_Interface $view = null)
{
$this->_view = $view;
return $this;
}
/**
* Retrieve view object
*
* If none registered, attempts to pull from ViewRenderer.
*
* @return Zend_View_Interface
*/
public function getView()
{
if (null === $this->_view) {
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$this->setView($viewRenderer->view);
}
return $this->_view;
}
/**
* Sets the functions to be used to apply to each value
* before display
*
* @param array $functions Default functions to escape values
*
* @return Bvb_Grid
*/
public function setDefaultEscapeFunction($functions)
{
$this->_escapeFunction = $functions;
return $this;
}
/**
* Returns the active escape functions
*
* @return string
*/
public function getDefaultEscapeFunction()
{
return $this->_escapeFunction;
}
/**
* Character encoding
*
* @param string $encoding Encoding to be used
*
* @return Bvb_Grid
*/
public function setcharEncoding($encoding)
{
$this->_charEncoding = $encoding;
return $this;
}
/**
* Returns the actual encoding
*
* @return string
*/
public function getCharEncoding()
{
return $this->_charEncoding;
}
/**
* The translator
*
* @param string $message Message to be translated
*
* @return string
*/
protected function __($message)
{
if (strlen($message) == 0) {
return $message;
}
if ($this->getTranslator()) {
return $this->getTranslator()->translate($message);
}
return $message;
}
/**
* Gets the translator instance
*
* @return Zend_Translate
*/
public function getTranslator()
{
return Bvb_Grid_Translator::getInstance()->getTranslator();
}
/**
* Check if a string is available
*
* @param string $message Message to check if it's translated
*
* @return bool
*/
protected function isTranslated($message)
{
return Bvb_Grid_Translator::getInstance()->isTranslated($message);
}
/**
* Use the overload function so we can return an object
*
* @param string $name Mehtod name
* @param string $value Mehtod args
*
* @return Bvb_Grid
*/
public function __call($name, $value)
{
if (substr(strtolower($name), 0, 6) == 'source') {
$meth = substr($name, 6);
$meth[0] = strtolower($meth[0]);
if (is_object($this->getSource()) && method_exists($this->getSource(), $meth)) {
$this->getSource()->$meth();
return $this;
}
}
$class = $this->_deployName;
if ($name == 'set' . ucfirst($class) . 'GridColumns') {
if (!isset($value[0]))
$value[0] = array();
$this->setGridColumns($value[0]);
return $this;
}
if ($name == 'set' . ucfirst($class) . 'DetailColumns') {
if (!isset($value[0]))
$value[0] = array();
$this->setDetailColumns($value[0]);
return $this;
}
if (substr(strtolower($name), 0, strlen($class) + 3) == 'set' . $class) {
$name = substr($name, strlen($class) + 3);
$name[0] = strtolower($name[0]);
$this->_deploy[$name] = $value[0];
return $this;
}
if (substr(strtolower($name), 0, 3) == 'set') {
$name = substr($name, 3);
if (!isset($value[0])) {
$value[0] = null;
}
$this->__set($name, $value[0]);
} else {
throw new Bvb_Grid_Exception("call to unknown function $name");
}
return $this;
}
/**
* Magic function handling
*
* @param string $var Variable name
* @param string $value Variable value
*
* @return Bvb_Grid
*/
public function __set($var, $value)
{
$var[0] = strtolower($var[0]);
$this->_info[$var] = $value;
return $this;
}
/**
* Update data from a column
*
* @param string $field Field Name
* @param array $options Associative array of options to be applyied to the field
*
* @return Bvb_Grid
*/
public function updateColumn($field, array $options = array())
{
$this->emitEvent('grid.update_column', array('field' => $field, 'options' => $options));
if (null == $this->getSource()
|| ($this->_allFieldsAdded == true && !array_key_exists($field, $this->_data['fields']))
) {
/**
* Add to the queue and call it from the getFieldsFromQuery() method
* @var $_updateColumnQueue
*/
if (isset($this->_updateColumnQueue[$field])) {
$this->_updateColumnQueue[$field] = array_merge($this->_updateColumnQueue[$field], $options);
} else {
$this->_updateColumnQueue[$field] = $options;
}
return $this;
}
if ($this->_allFieldsAdded == false) {
$this->_data['fields'][$field] = $options;
} elseif (array_key_exists($field, $this->_data['fields'])) {
if (isset($options['hRow']) && $options['hRow'] == 1) {
$options['title'] = isset($options['title']) ? $options['title'] : $this->_data['fields'][$field]['field'];
$this->_info['hRow'] = array('field' => $field, 'title' => $options['title']);
}
$this->_data['fields'][$field] = array_merge($this->_data['fields'][$field], $options);
}
return $this;
}
/**
* Set option hidden=1 on several columns
*
* @param array $columns Array of columns that will be hidden
*
* @return Bvb_Grid
*/
public function setColumnsHidden(array $columns)
{
foreach ($columns as $column) {
$this->updateColumn($column, array('hidden' => 1));
}
return $this;
}
/**
* Set option hidden=0 on several columns
*
* @param array $columns Array of columns that will be displayed
*
* @return Bvb_Grid
*/
public function setColumnsVisible(array $columns)
{
$this->setColumnsHidden($this->getFields());
foreach ($columns as $column) {
$this->updateColumn($column, array('hidden' => false));
}
return $this;
}
/**
* Defines columns positions.
*
* Hither define array('field'=>position) or array(field1, field2)
*
* @param array $columns
* @return Bvb_Grid
*/
public function setColumnsPositions(array $columns)
{
if (isset($columns[0])) {
$columns = array_flip($columns);
}
foreach ($columns as $field => $position) {
$this->updateColumn($field, array('position' => $position));
}
return $this;
}
/**
* Add a new dir to look for when formating a field
*
* @param string $dir Classes Location
* @param string $prefix Classes prefix
*
* @return Bvb_Grid
*/
public function addFormatterDir($dir, $prefix)
{
$this->_formatter->addPrefixPath(trim($prefix, '_'), trim($dir, '/') . '/');
return $this;
}
/**
* Format a field
*
* @param string $value Value to be formatted
* @param mixed $formatter Formatter to be used
*
* @return mixed
*/
protected function _applyFormat($value, $formatter)
{
if (is_array($formatter)) {
$formatter = array_values($formatter);
$result = reset($formatter);
if (!isset($formatter[1])) {
$formatter[1] = array();
}
$options = (array) $formatter[1];
} else {
$result = $formatter;
$options = array();
}
$class = $this->_formatter->load($result);
$t = new $class($options);
if (!$t instanceof Bvb_Grid_Formatter_FormatterInterface) {
throw new Bvb_Grid_Exception("$class must implement the Bvb_Grid_Formatter_FormatterInterface");
}
return $t->format($value);
}
/**
* Number of records to show per page
*
* @param array $pagination key=>pair array of possible values of records per page for user to choose from
*
* @return Bvb_Grid
*/
public function setPaginationInterval(array $pagination)
{
$this->_paginationInterval = $pagination;
return $this;
}
/**
* Returns current pagination interval configurations
*
* @return array
*/
public function getPaginationInterval()
{
return $this->_paginationInterval;
}
/**
* Number of records to show per page
*
* @param int $number Records to show
*
* @return Bvb_Grid
*/
public function setRecordsPerPage($number = 15)
{
$this->_recordsPerPage = (int) $number;
return $this;
}
/**
* Default values for filters.
* This will be applied before displaying. However the user can still remove them.
*
* @param array $filters Associative array with fields=>Values to define default filters values
*
* @return Bvb_Grid
*/
public function setDefaultFiltersValues(array $filters)
{
$this->_defaultFilters = $filters;
return $this;
}
/**
* Get filters values
*
* @return Bvb_Grid
*/
protected function _buildFiltersValues()
{
//Build an array to know filters values
$filtersValues = array();
$fields = $this->getFields();
$filters = array();
foreach ($this->_ctrlParams as $key => $value) {
// only build filter if search is enabled
if (isset($this->_data['fields'][$key]['search']) && $this->_data['fields'][$key]['search'] == false)
continue;
//This happens when we have range filters and the url look like this:
// /action/field[from]/100/field[to]/500
if (stripos($key, '[')) {
$name = explode('[', $key);
//lets check if there ir a grid id, so we can remove it
if (strlen($this->getGridId()) > 0) {
$name[0] = substr($name[0], 0, - strlen($this->getGridId()));
}
//check if this param is in fact a field we set
if (in_array($name[0], $fields)) {
$filters[$name[0]][substr($name[1], 0, - 1)] = $value;
}
} else {
//check if this param is in fact a field we set
if (in_array($key, $fields)) {
$filters[$key] = $value;
//Can have a grid id, so we also need to check for that situation
} elseif (in_array(substr($key, 0, - strlen($this->getGridId())), $fields)) {
if ($this->getGridId() != ''
&& substr($key, - strlen($this->getGridId())) == $this->getGridId()
) {
$key = substr($key, 0, - strlen($this->getGridId()));
}
$filters[$key] = $value;
}
}
}
if (count($filters) > 0) {
//let's set the range filters as an array
foreach ($filters as $key => $value) {
if (is_array($value)) {
$this->setParam($key, $value);
}
}
$fieldsRaw = $this->_data['fields'];
//final check for allowed fields
foreach ($filters as $key => $filter) {
if (!is_array($filter) && (strlen($filter) == 0 || !in_array($key, $this->_fields))) {
unset($filters[$key]);
} elseif (!is_array($filter)) {
if (isset($fieldsRaw[$key]['searchField'])) {
$key = $fieldsRaw[$key]['searchField'];
}
//Copy the current filter value so we can perform the vairous options and not loosing the
//orignal value. This happens with transform, callbacks, etc,
$oldFilter = $filter;
//Check fi user has defined a transform option for the value
//The transform option is used to normalise vallues, like date, currency, etc
if (isset($this->_filters[$key]['transform']) && is_callable($this->_filters[$key]['transform'])) {
$filter = call_user_func($this->_filters[$key]['transform'], $filter);
}
//A callback is set? If yes, let's call it
if (isset($this->_filters[$key]['callback']) && is_array($this->_filters[$key]['callback'])) {
if (!is_callable($this->_filters[$key]['callback']['function'])) {
throw new Bvb_Grid_Exception($this->_filters[$key]['callback']['function']
. ' is not callable');
}
if (!isset($this->_filters[$key]['callback']['params'])
|| !is_array($this->_filters[$key]['callback']['params'])
) {
$this->_filters[$key]['callback']['params'] = array();
}
$this->_filters[$key]['callback']['params'] = array_merge(
$this->_filters[$key]['callback']['params'], array('field' => $key,
'value' => $filter,
'select' => $this->getSource()->getSelectObject())
);
$result = call_user_func($this->_filters[$key]['callback']['function'], $this->_filters[$key]['callback']['params']
);
} elseif (isset($this->_data['fields'][$key]['search'])
&& is_array($this->_data['fields'][$key]['search'])
&& $this->_data['fields'][$key]['search']['fulltext'] == true
) {
//Fulltext search activated by user. Only possible in MySQL server
$this->getSource()->addFullTextSearch($filter, $this->_data['fields'][$key]);
} else {
//Nothing "special" needs to be performed. So we continue with the normal procedure
//Let's check if there is a special symbol in user's input
//Some exaemples: =valu, >value, r:regexp
$op = $this->getFilterOp($key, $filter);
$this->emitEvent('source.add_condition', array('filter' => &$filter, 'op' => &$op, 'field' => &$completeField));
$this->getSource()->addCondition($op['filter'], $op['op'], $this->_data['fields'][$key]);
}
//We assign the filter value so it can be filled properlly.
//Even if we perform any transform to the field, the original user's input must be showed
$filtersValues[$key] = $oldFilter;
}
if (is_array($filter)) {
//Load filter render
$render = $this->loadFilterRender($this->_filters[$key]['render']);
$render->setFieldName($key);
if ($render->hasConditions()) {
$cond = $render->getConditions();
$render->setSelect($this->getSource()->getSelectObject());
foreach ($filter as $nkey => $value) {
if (strlen($value) > 0) {
$oldValue = $value;
$value = $render->normalize($value, $nkey);
$this->emitEvent('source.add_condition', array('filter' => &$filter, 'op' => &$op, 'field' => &$completeField));
$this->getSource()->addCondition($value, $cond[$nkey], $this->_data['fields'][$key]);
$filtersValues[$key][$nkey] = $oldValue;
}
}
} else {
$render->buildQuery($filter);
}
}
}
}
$this->_filtersValues = $filtersValues;
$this->_applyExternalFilters();
//If needed put current filters values in session
if (count($this->_filtersValues) > 0 && $this->_paramsInSession === true) {
$this->_sessionParams->filters = $this->_filtersValues;
}
return $this;
}
/**
* Adds external filters to the grid
*
* @return void
*/
protected function _applyExternalFilters()
{
if (count($this->_externalFilters) == 0)
return false;
foreach ($this->_externalFilters as $id => $callback) {
$val = $this->getRequestParamClean($id);
if ($val) {
call_user_func_array($callback, array($id, $val, $this->getSelect()));
$this->_filtersValues[$id] = $this->getRequestParamClean($id);
}
}
}
/**
* Returns the operand to be used in filters
* This value comes from the user input
* but can be override
*
* @param string $field Field name
* @param string $filter Filter to apply to the field
*
* @return array
*/
public function getFilterOp($field, $filter)
{
if (!isset($this->_data['fields'][$field]['searchType'])) {
$this->_data['fields'][$field]['searchType'] = 'like';
}
$op = strtolower($this->_data['fields'][$field]['searchType']);
if ($this->_data['fields'][$field]['searchType'] == 'sqlExp'
&& isset($this->_data['fields'][$field]['searchSqlExp'])
) {
$op = 'sqlExp';
$sqlExp = $this->_data['fields'][$field]['searchSqlExp'];
if (!isset($this->_data['fields'][$field]['searchSqlQuote'])) {
$this->_data['fields'][$field]['searchSqlQuote'] = false;
}
$sqlQuote = (bool) $this->_data['fields'][$field]['searchSqlQuote'];
if ($sqlQuote === false) {
$filter = str_replace('{{value}}', $this->getSource()->quoteValue($filter), $sqlExp);
} else {
$filter = str_replace('{{value}}', trim(subtr($filter, 1, -1)), $sqlExp);
}
} elseif (substr(strtolower($filter), 0, 6) == ':empty') {
$op = 'empty';
$filter = substr($filter, 2);
} elseif (substr(strtolower($filter), 0, 10) == ':isnotnull') {
$op = 'isnotnull';
$filter = substr($filter, 2);
} elseif (substr(strtolower($filter), 0, 7) == ':isnull') {
$op = 'isnull';
$filter = substr($filter, 2);
} elseif (substr(strtoupper($filter), 0, 2) == 'R:') {
$op = 'REGEX';
$filter = substr($filter, 2);
} elseif (strpos($filter, '<>') !== false && substr($filter, 0, 2) != '<>') {
$op = 'range';
} elseif (substr($filter, 0, 1) == '=') {
$op = '=';
$filter = substr($filter, 1);
} elseif (substr($filter, 0, 2) == '>=') {
$op = '>=';
$filter = substr($filter, 2);
} elseif ($filter[0] == '>') {
$op = '>';
$filter = substr($filter, 1);
} elseif (substr($filter, 0, 2) == '<=') {
$op = '<=';
$filter = substr($filter, 2);
} elseif (substr($filter, 0, 2) == '<>' || substr($filter, 0, 2) == '!=') {
$op = '<>';
$filter = substr($filter, 2);
} elseif ($filter[0] == '<') {
$op = '<';
$filter = substr($filter, 1);
} elseif ($filter[0] == '*' and substr($filter, - 1) == '*') {
$op = 'like';
$filter = substr($filter, 1, - 1);
} elseif ($filter[0] == '*' and substr($filter, - 1) != '*') {
$op = 'llike';
$filter = substr($filter, 1);
} elseif ($filter[0] != '*' and substr($filter, - 1) == '*') {
$op = 'rlike';
$filter = substr($filter, 0, - 1);
} elseif (stripos($filter, ',') !== false) {
$op = 'IN';
} elseif (substr($filter, 0, 2) == '||') {
$op = '||';
$filter = substr($filter, 2);
}
if (isset($this->_data['fields'][$field]['searchTypeFixed'])
&& $this->_data['fields'][$field]['searchTypeFixed'] == true
&& $op != $this->_data['fields'][$field]['searchType']
) {
$op = $this->_data['fields'][$field]['searchType'];
}
return array('op' => $op, 'filter' => $filter);
}
/**
* Build query.
*
* @return bool
*/
protected function _buildQueryOrderAndLimit()
{
$start = (int) $this->getParam('start');
$order = $this->getParam('order');
$order1 = explode('_', $order);
$orderf = strtoupper(end($order1));
array_pop($order1);
$orderField = implode('_', $order1);
if (!isset($this->_fieldsOrder[$orderField])) {
$this->clearParam('order');
$orderf = false;
} else {
$orderField = $this->_fieldsOrder[$orderField];
}
if ($orderf == 'DESC'
|| $orderf == 'ASC'
|| ($this->_paramsInSession === true
&& is_array($this->_sessionParams->order))
) {
if ($this->_paramsInSession === true) {
if ($this->getParam('noOrder')) {
$this->_sessionParams->order = null;
}
if (is_array($this->_sessionParams->order) && !$this->getParam('order')) {
$orderField = $this->_sessionParams->order['field'];
$orderf = $this->_sessionParams->order['order'];
$this->setParam('order' . $this->getGridId(), $orderField . '_' . $orderf);
}
}
if (in_array($orderField, $this->_fieldsOrder)) {
$this->getSource()->buildQueryOrder($orderField, $orderf, true);
if ($this->_paramsInSession === true) {
$this->_sessionParams->order = array('field' => $orderField, 'order' => $orderf);
}
}
}
$this->getSource()->buildQueryLimit($this->getRecordsPerPage(), $start);
return true;
}
/**
* Returns the number of records to show per page
*
* @return integer
*/
public function getRecordsPerPage()
{
$perPage = (int) $this->getParam('perPage', 0);
if ($this->_paramsInSession === true && $this->getParam('perPage') === false) {
$perPage = (int) $this->_sessionParams->perPage;
$this->setParam('perPage' . $this->getGridId(), $perPage);
}
if ($perPage > 0 && array_key_exists($perPage, $this->_paginationInterval)) {
if ($this->_paramsInSession === true) {
$this->_sessionParams->perPage = $perPage;
}
return $perPage;
} else {
if ($this->_paramsInSession === true) {
$this->_sessionParams->perPage = $this->_recordsPerPage;
}
return $this->_recordsPerPage;
}
}
/**
* Returns the url, without the param(s) specified
*
* @param mixed $situation Array of params to be removed
* @param array $extraParams param to add to url
*
* @todo Use a view helper to build url
*
* @return string
*/
public function getUrl($situation = '', array $extraParams = array())
{
$situation = (array) $situation;
//this array the a list of params that name changes
//based on grid id. The id is prepended to the name
$paramsGet = array('perPage',
'order',
'start',
'filters',
'zfmassedit',
'zfmassremove',
'send_',
'postMassIds',
'gridAction_',
'massActionsAll_',
'noFilters',
'_exportTo',
'add',
'edit',
'noOrder',
'comm',
'detail',
'delete');
$params = $this->getParams();
if (in_array('filters', $situation)) {
$fields = array_merge($this->getFields(), array_keys($this->_externalFilters));
foreach(array_keys($this->_externalFilters) as $removeExternalFilter)
{
unset($params[$removeExternalFilter]);
}
foreach ($fields as $field) {
if (isset($params[$field . $this->getGridId()])) {
unset($params[$field . $this->getGridId()]);
}
}
foreach ($params as $key => $value) {
if (stripos($key, '[') !== false) {
$fl = explode('[', $key);
if (in_array(rtrim($fl[0], $this->getGridId()), $fields)) {
unset($params[rtrim($fl[0]) . '[' . $fl[1]]);
$fieldName = substr(rtrim($fl[0]), 0, strpos(rtrim($fl[0]), $this->getGridId()));
if(in_array($fieldName, $this->_fields))
$this->clearParam($fieldName);
}
}
}
}
foreach ($situation as $value) {
if (in_array($value, $paramsGet)) {
$value = $value . $this->getGridId();
}
unset($params[$value]);
}
$paramsClean = $params;
unset($paramsClean['_zfgid']);
unset($paramsClean['gridmod' . $this->getGridId()]);
$this->clearParam('gridmod');
if (is_array($this->_filters)) {
foreach ($this->_filters as $key => $value) {
if (is_array($key) && isset($key['render'])) {
unset($paramsClean[$key]);
}
}
}
foreach ($extraParams as $key => $value) {
if ($this->getGridId()) {
$extraParams[$key . $this->getGridId()] = $value;
unset($extraParams[$key]);
}
}
$extraParams['zfghost'] = 1;
$paramsClean = array_merge($paramsClean, (array) $extraParams);
$ur = new Zend_View_Helper_Url();
$url = $ur->url($paramsClean, null);
return str_replace("/zfghost/1", '', $url);
}
/**
* Return variable stored in info. Return default if value is not stored.
*
* @param string $param Param to look for in the info var
* @param mixed $default Return this value if param does not exist
*
* @return string
*/
public function getInfo($param, $default = false)
{
if (isset($this->_info[$param]))
return $this->_info[$param];
if (strpos($param, ',')) {
$params = explode(',', $param);
$param = array_map('trim', $params);
$final = $this->_info;
foreach ($params as $check) {
if (!isset($final[$check])) {
return $default;
}
$final = $final[$check];
}
return $final;
}
return $default;
}
/**
* Build Filters. If defined put the values
* Also check if the user wants to hide a field
*
* @return mixed
*/
protected function _buildFilters()
{
$return = array();
if ($this->getInfo('noFilters') == 1) {
return false;
}
$data = $this->_fields;
foreach ($this->_extraColumns as $key => $value) {
if ($value['position'] == 'left') {
$value['newrow'] = !isset($value['newrow']) ? false : $value['newrow'];
$value['rowspan'] = !isset($value['rowspan']) ? null : $value['rowspan'];
$value['colspan'] = !isset($value['colspan']) ? null : $value['colspan'];
$return[$key] = array('type' => 'extraField',
'position' => 'left',
'newrow' => $value['newrow'],
'rowspan' => $value['rowspan'],
'colspan' => $value['colspan']);
}
}
for ($i = 0; $i < count($data); $i++) {
$nf = $this->_fields[$i];
if (!isset($this->_data['fields'][$nf]['search'])) {
$this->_data['fields'][$nf]['search'] = true;
}
if ($this->_displayField($nf)) {
if (!isset($this->_data['fields'][$nf]['newrow'])) {
$newrow = false;
} else {
$newrow = $this->_data['fields'][$nf]['newrow'];
}
if (!isset($this->_data['fields'][$nf]['rowspan'])) {
$rowspan = null;
} else {
$rowspan = $this->_data['fields'][$nf]['rowspan'];
}
if (!isset($this->_data['fields'][$nf]['colspan'])) {
$colspan = null;
} else {
$colspan = $this->_data['fields'][$nf]['colspan'];
}
if (is_array($this->_filters)
&& array_key_exists($data[$i], $this->_filters)
&& $this->_data['fields'][$nf]['search'] != false
) {
$filterValue = isset($this->_filtersValues[$data[$i]]) ? $this->_filtersValues[$data[$i]] : '';
$return[] = array('type' => 'field',
'value' => $filterValue,
'field' => $data[$i],
'newrow' => $newrow,
'rowspan' => $rowspan,
'colspan' => $colspan);
} else {
$return[] = array('type' => 'field',
'field' => $data[$i],
'newrow' => $newrow,
'rowspan' => $rowspan,
'colspan' => $colspan);
}
}
}
foreach ($this->_extraColumns as $key => $value) {
if ($value['position'] == 'right') {
$value['newrow'] = !isset($value['newrow']) ? false : $value['newrow'];
$value['rowspan'] = !isset($value['rowspan']) ? null : $value['rowspan'];
$value['colspan'] = !isset($value['colspan']) ? null : $value['colspan'];
$return[$key] = array('type' => 'extraField',
'position' => 'right',
'newrow' => $value['newrow'],
'rowspan' => $value['rowspan'],
'colspan' => $value['colspan']);
}
}
return $return;
}
/**
* Checks if a field should be displayed or is setted as 'remove'
*
* @param string $field Field Name
*
* @return bool
*/
protected function _displayField($field)
{
if (!isset($this->_data['fields'][$field]['remove'])) {
$this->_data['fields'][$field]['remove'] = false;
}
if (!isset($this->_data['fields'][$field]['hidden'])) {
$this->_data['fields'][$field]['hidden'] = false;
}
if ($this->_data['fields'][$field]['remove'] == 0
&& (($this->_data['fields'][$field]['hidden'] == 0)
|| ($this->_data['fields'][$field]['hidden'] == 1 && $this->_removeHiddenFields !== true))
) {
return true;
}
return false;
}
/**
* Replaces the brackets in fields
*
* @param array $fields Array of fields
*
* @return array
*/
protected function _prepareReplace($fields)
{
// Make an array of field names in format {{$fieldname}}
$map = array_map(create_function('$value', 'return "{{{$value}}}";'), $fields);
if (isset($this->_options['grid']['enableUnmodifiedFieldPlaceholders'])
&& $this->_options['grid']['enableUnmodifiedFieldPlaceholders'] == true
) {
// Enable placeholders for unmodified fields: Make an array of field names in format {{=$fieldname}}
$map2 = array_map(create_function('$value', 'return "{{={$value}}}";'), $fields);
$map = array_merge($map, $map2);
}
return $map;
}
/**
* Build the titles with the order links (if wanted)
*
* @return array
*/
protected function _buildTitles()
{
static $index = 0;
$return = array();
$url = $this->getUrl(array('order', 'start', 'comm', 'noOrder'));
foreach ($this->getExtraColumnsForPosition('left') as $key => $value) {
$index++;
$value['newrow'] = !isset($value['newrow']) ? false : $value['newrow'];
$value['rowspan'] = !isset($value['rowspan']) ? null : $value['rowspan'];
$value['colspan'] = !isset($value['colspan']) ? null : $value['colspan'];
if ($this->__(isset($value['title']))) {
$fieldValue = $value['title'];
} else {
$fieldValue = $value['name'];
}
$return[$index . '-' . $key] = array('type' => 'extraField',
'value' => $fieldValue,
'position' => 'left',
'newrow' => $value['newrow'],
'rowspan' => $value['rowspan'],
'colspan' => $value['colspan']);
}
$titles = $this->_fields;
if (!$this->getParam('noOrder')) {
$selectOrder = $this->getSource()->getSelectOrder();
if (count($selectOrder) == 1) {
$this->setParam('order' . $this->getGridId(), $selectOrder[0] . '_' . strtoupper($selectOrder[1]));
}
}
for ($i = 0; $i < count($this->_fields); $i++) {
if ($this->getParam('order')) {
$explode = explode('_', $this->getParam('order'));
$name = str_replace('_' . end($explode), '', $this->getParam('order'));
$this->_order[$name] = strtoupper(end($explode)) == 'ASC' ? 'DESC' : 'ASC';
}
$fieldsToOrder = array_values($this->_data['fields']);
if (isset($fieldsToOrder[$i]['orderField']) && strlen($fieldsToOrder[$i]['orderField']) > 0) {
$orderFinal = $fieldsToOrder[$i]['orderField'];
} else {
$orderFinal = $titles[$i];
}
if (is_array($this->_order)) {
$order = $orderFinal == key($this->_order) ? $this->_order[$orderFinal] : 'ASC';
} else {
$order = 'ASC';
}
if ($this->_displayField($titles[$i])) {
if (!isset($this->_data['fields'][$titles[$i]]['newrow'])) {
$newrow = false;
} else {
$newrow = $this->_data['fields'][$titles[$i]]['newrow'];
}
if (!isset($this->_data['fields'][$titles[$i]]['rowspan'])) {
$rowspan = null;
} else {
$rowspan = $this->_data['fields'][$titles[$i]]['rowspan'];
}
if (!isset($this->_data['fields'][$titles[$i]]['colspan'])) {
$colspan = null;
} else {
$colspan = $this->_data['fields'][$titles[$i]]['colspan'];
}
$noOrder = $this->getInfo('noOrder') ? $this->getInfo('noOrder') : '';
if ($this->isTranslated($titles[$i]) === true) {
$fieldTitle = $this->__($titles[$i]);
} else {
$fieldTitle = $this->__($this->_titles[$titles[$i]]);
}
if ($noOrder == 1) {
$return[$titles[$i]] = array('type' => 'field',
'name' => $titles[$i],
'field' => $titles[$i],
'value' => $fieldTitle,
'newrow' => $newrow,
'rowspan' => $rowspan,
'colspan' => $colspan);
} else {
$return[$titles[$i]] = array('type' => 'field',
'name' => $titles[$i],
'field' => $orderFinal,
'simpleUrl' => $this->getUrl(array('order', 'start', 'comm', 'noOrder')),
'url' => $this->getUrl(array('order', 'start', 'comm', 'noOrder'), array('order' => $orderFinal . "_" . $order)),
'value' => $fieldTitle,
'newrow' => $newrow,
'rowspan' => $rowspan,
'colspan' => $colspan);
}
}
}
foreach ($this->getExtraColumnsForPosition('right') as $key => $value) {
$index++;
$value['newrow'] = !isset($value['newrow']) ? false : $value['newrow'];
$value['rowspan'] = !isset($value['rowspan']) ? null : $value['rowspan'];
$value['colspan'] = !isset($value['colspan']) ? null : $value['colspan'];
$return[$index . '-' . $key] = array('type' => 'extraField',
'value' => $this->__(isset($value['title']) ? $value['title'] : $value['name']),
'position' => 'right',
'newrow' => $value['newrow'],
'rowspan' => $value['rowspan'],
'colspan' => $value['colspan']);
}
$this->_finalFields = $return;
return $return;
}
/**
* Replaces {{field}} for the actual field value
*
* @param string &$item Item to apply function
* @param string $key Value to search
* @param string $text Value to replace
*
* @return void
*/
protected function _replaceSpecialTags(&$item, $key, $text)
{
$item = str_replace($text['find'], $text['replace'], $item);
}
/**
* Applies the format option to a field
*
* @param string $newValue Value generated
* @param string $value Field Name
* @param array $search Variables to search for
* @param array $replace Replace variable with these values
*
* @return mixed
*/
protected function _applyFieldFormat($newValue, $value, $search, $replace)
{
if (is_array($value)) {
array_walk_recursive($value, array($this, '_replaceSpecialTags'), array('find' => $search, 'replace' => $replace));
}
return $this->_applyFormat($newValue, $value);
}
/**
* Applies the callback option to a field
*
* @param string $newValue Value generated
* @param string $value Field Name
* @param array $search Variables to search for
* @param array $replace Replace variable with these values
* @param string $field Current field
*
* @return mixed
*/
protected function _applyFieldCallback($newValue, $value, $search, $replace, $field)
{
if (is_string($value)) {
$value = array('function' => $value);
}
if (!is_callable($value['function'])) {
throw new Bvb_Grid_Exception($value['function'] . ' not callable');
}
if (isset($value['params']) && is_array($value['params'])) {
$toReplace = $value['params'];
$toReplaceArray = array();
$toReplaceObj = array();
foreach ($toReplace as $key => $rep) {
if (is_scalar($rep) || is_array($rep)) {
$toReplaceArray[$key] = $rep;
} else {
$toReplaceObj[$key] = $rep;
}
}
} else {
return call_user_func($value['function'], $replace[$field]);
}
if (is_array($toReplace)) {
array_walk_recursive(
$toReplaceArray, array($this, '_replaceSpecialTags'), array('find' => $search, 'replace' => $replace)
);
}
for ($i = 0; $i <= count($toReplace); $i++) {
if (isset($toReplaceArray[$i])) {
$toReplace[$i] = $toReplaceArray[$i];
} elseif (isset($toReplaceObj[$i])) {
$toReplace[$i] = $toReplaceObj[$i];
}
}
$toReplace = str_replace($search, $replace, $toReplace);
$toReplace = $this->_checkForAllParamsInField($toReplace, $replace);
return call_user_func_array($value['function'], $toReplace);
}
protected function _checkForAllParamsInField($params, $fields)
{
foreach ($params as $key => $dec) {
if ($dec == '{{_ALL_}}' || $dec == '{{=_ALL_}}') {
$params[$key] = $fields;
}
}
return $params;
}
/**
* Applies the decorator to a fields
*
* @param array $find Variables to search for
* @param array $replace Replace variable with these values
* @param string $value Field Name
*
* @return string
*/
protected function _applyFieldDecorator(array $find, array $replace, $value)
{
return str_replace($find, $replace, $value);
}
/**
* Applies escape functions to a field
*
* @param string $value Field Value
*
* @return string
*/
protected function _applyFieldEscape($value)
{
if ($this->_escapeFunction === false) {
return $value;
}
if (!is_callable($this->_escapeFunction)) {
throw new Bvb_Grid_Exception($this->_escapeFunction . ' not callable');
}
$value = call_user_func($this->_escapeFunction, $value);
return $value;
}
/**
* Apply escape functions to column
*
* @param string $field Field Name
* @param string $value Field Value
*
* @return mixed
*/
private function _escapeField($field, $value)
{
if (!isset($this->_data['fields'][$field]['escape'])) {
$this->_data['fields'][$field]['escape'] = 1;
}
if (($this->_data['fields'][$field]['escape'] ? 1 : 0) == 0) {
return $value;
}
if ($this->_data['fields'][$field]['escape'] == 1) {
return $this->_applyFieldEscape($value);
}
if (!is_callable($this->_data['fields'][$field]['escape'])) {
throw new Bvb_Grid_Exception($this->_data['fields'][$field]['escape'] . ' not callable');
}
return call_user_func($this->_data['fields'][$field]['escape'], $value);
}
/**
* Applies the view helper to the field
*
* @param string $newValue Value generated
* @param string $value Field Name
* @param array $search Variables to search for
* @param array $replace Replace variable with these values
*
* @return string
*/
protected function _applyFieldHelper($newValue, $value, array $search, array $replace)
{
if (is_array($value)) {
array_walk_recursive($value, array($this, '_replaceSpecialTags'), array('find' => $search, 'replace' => $replace));
}
$name = $value['name'];
$t = $this->getView()->getHelper($name);
$re = new ReflectionMethod($t, $name);
if (isset($value['params']) && is_array($value['params'])) {
$newValue = $re->invokeArgs($t, $value['params']);
} else {
$newValue = $re->invoke($t);
}
return $newValue;
}
/**
* The loop for the results.
* Check the extra-fields,
*
* @return array
*/
protected function _buildGrid($data = null)
{
$return = array();
$i = 0;
if ($data === null) {
$result = $this->_result;
$fields = $this->_fields;
} else {
$fields = array_keys($data[0]);
$result = $data;
}
$classConditional = array();
foreach ($result as $row) {
$search = $this->_prepareReplace($this->_fields);
// Create a map of field values with which to replace special field placeholders (ex. {{field_name}})
$replace = array();
foreach ($fields as $field) {
$row[$field] = isset($row[$field]) ? $row[$field] : null;
$replace[$field] = $row[$field];
}
if (isset($this->_options['grid']['enableUnmodifiedFieldPlaceholders'])
&& $this->_options['grid']['enableUnmodifiedFieldPlaceholders'] == true
) {
// Enable placeholders for unmodified fields:
// Append a second set of fields to the replacement map, with field names prefixed by '='
// (ex. {{=field_name}})
// These will allow access to the original field values unmodified by formatters, etc.
foreach ($fields as $field) {
$row[$field] = isset($row[$field]) ? $row[$field] : null;
$replace['=' . $field] = $row[$field];
}
}
$replace['editUrl'] = str_replace($search, $replace, $this->_actionsUrls['edit']);
$replace['addUrl'] = str_replace($search, $replace, $this->_actionsUrls['add']);
$replace['deleteUrl'] = str_replace($search, $replace, $this->_actionsUrls['delete']);
$replace['detailUrl'] = str_replace($search, $replace, $this->_actionsUrls['detail']);
if (!in_array('{{editUrl}}', $search)) {
$search[] = '{{editUrl}}';
}
if (!in_array('{{addUrl}}', $search)) {
$search[] = '{{addUrl}}';
}
if (!in_array('{{deleteUrl}}', $search)) {
$search[] = '{{deleteUrl}}';
}
if (!in_array('{{detailUrl}}', $search)) {
$search[] = '{{detailUrl}}';
}
$this->_classRowConditionResult[$i] = '';
if (isset($this->_classRowCondition[0]) && is_array($this->_classRowCondition[0])) {
foreach ($this->_classRowCondition as $value) {
$cond = str_replace($search, $replace, $value['condition']);
$final = call_user_func(create_function('', "if($cond){return true;}else{return false;}"));
$this->_classRowConditionResult[$i] .= $final == true ? $value['class'] . ' ' : $value['else'] . ' ';
}
}
$this->_classRowConditionResult[$i] .= ( $i % 2) ? $this->_cssClasses['even'] : $this->_cssClasses['odd'];
if (count($this->_classCellCondition) > 0) {
foreach ($this->_classCellCondition as $key => $value) {
$classConditional[$key] = '';
foreach ($value as $condF) {
$cond = str_replace($search, $replace, $condF['condition']);
$final = call_user_func(create_function('', "if($cond){return true;}else{return false;}"));
$classConditional[$key] .= $final == true ? $condF['class'] . ' ' : $condF['else'] . ' ';
}
}
}
/**
* Deal with extrafield from the left
*/
$left = $this->getExtraColumnsForPosition('left');
foreach ($left as $field) {
$return[$i][] = $this->_buildExtraField($field, $search, $replace);
}
/**
* Deal with the grid itself
*/
foreach ($fields as $field) {
$row[$field] = isset($row[$field]) ? $row[$field] : null;
$newValue = $this->_escapeField($field, $row[$field]);
if (isset($this->_data['fields'][$field]['callback']['function'])) {
$newValue = $this->_applyFieldCallback(
$newValue, $this->_data['fields'][$field]['callback'], $search, $replace, $field
);
$replace[$field] = $newValue;
$search[] = '{{callback}}';
$replace[] = $newValue;
}
if (isset($this->_data['fields'][$field]['format'])) {
$newValue = $this->_applyFieldFormat(
$newValue, $this->_data['fields'][$field]['format'], $search, $replace
);
$replace[$field] = $newValue;
$search[] = '{{format}}';
$replace[] = $newValue;
}
if (isset($this->_data['fields'][$field]['helper'])) {
$newValue = $this->_applyFieldHelper(
$newValue, $this->_data['fields'][$field]['helper'], $search, $replace
);
$replace[$field] = $newValue;
$search[] = '{{helper}}';
$replace[] = $newValue;
}
if (isset($this->_data['fields'][$field]['decorator'])) {
$newValue = $this->_applyFieldDecorator(
$search, $replace, $this->_data['fields'][$field]['decorator']
);
}
if ($this->_displayField($field)) {
if (isset($this->_data['fields'][$field]['translate'])
&& $this->_data['fields'][$field]['translate'] == true
) {
$newValue = $this->__($newValue);
}
if (!isset($this->_data['fields'][$field]['style'])) {
$style = '';
} else {
$style = $this->_data['fields'][$field]['style'];
}
if (isset($this->_data['fields'][$field]['class'])) {
$fieldClass = $this->_data['fields'][$field]['class'];
} else {
$fieldClass = '';
}
if (isset($classConditional[$field])) {
$finalClassConditional = $classConditional[$field];
} else {
$finalClassConditional = '';
}
if (!isset($this->_data['fields'][$field]['newrow'])) {
$newrow = false;
} else {
$newrow = $this->_data['fields'][$field]['newrow'];
}
if (!isset($this->_data['fields'][$field]['rowspan'])) {
$rowspan = null;
} else {
$rowspan = $this->_data['fields'][$field]['rowspan'];
}
if (!isset($this->_data['fields'][$field]['colspan'])) {
$colspan = null;
} else {
$colspan = $this->_data['fields'][$field]['colspan'];
}
$return[$i][] = array('class' => $fieldClass . ' ' . $finalClassConditional,
'value' => $newValue,
'field' => $field,
'type' => 'field',
'style' => $style,
'newrow' => $newrow,
'rowspan' => $rowspan,
'colspan' => $colspan);
}
}
/**
* Deal with extra fields from the right
*/
foreach ($this->getExtraColumnsForPosition('right') as $field) {
$return[$i][] = $this->_buildExtraField($field, $search, $replace);
}
$i++;
}
return $return;
}
/**
* Get the extra fields for a give position
*
* @param string $position Postion name
*
* @return array
*/
public function getExtraColumnsForPosition($position = 'left')
{
if (!is_array($this->_extraColumns)) {
return array();
}
$final = array();
foreach ($this->getExtraColumns() as $value) {
if ($value['position'] == $position) {
$final[] = $value;
}
}
$newOrder = array();
foreach ($final as $key => $value) {
$newOrder[$key] = (int)$value['order'];
}
array_multisort( $newOrder, SORT_ASC, $final);
return $final;
}
/**
* Build extra fields (apply callbacks, helpers, etc)
*
* @param string $field Field Name
* @param array $search Variables to search for
* @param array $replace Replace variable with these values
*
* @return array
*/
protected function _buildExtraField($field, $search, $replace)
{
$originalArray = array('class' => '', 'style' => '', 'newrow' => '', 'rowspan' => '', 'colspan' => '');
$field = array_merge($originalArray, $field);
$value = '';
if (isset($field['format'])) {
$value = $this->_applyFieldFormat($value, $field['format'], $search, $replace);
$search[] = '{{format}}';
$replace[] = $value;
}
if (isset($field['callback'])) {
$value = $this->_applyFieldCallback($value, $field['callback'], $search, $replace, $field);
$search[] = '{{callback}}';
$replace[] = $value;
}
if (isset($field['helper'])) {
$value = $this->_applyFieldHelper($value, $field['helper'], $search, $replace);
$search[] = '{{helper}}';
$replace[] = $value;
}
if (isset($field['decorator'])) {
$value = $this->_applyFieldDecorator($search, $replace, $field['decorator']);
}
return array('class' => $field['class'],
'value' => $value,
'type' => 'extraField',
'field' => $field['name'],
'style' => $field['style'],
'newrow' => $field['newrow'],
'rowspan' => $field['rowspan'],
'colspan' => $field['colspan']);
}
/**
* Apply SQL Functions
*
* @param array $where Where condition to be applied
*
* @return array
*/
protected function _buildSqlExp($where = array())
{
$final = $this->getInfo('sqlexp') ? $this->getInfo('sqlexp') : '';
if (!is_array($final)) {
return false;
}
$result = array();
foreach ($final as $key => $value) {
if (!array_key_exists($key, $this->_data['fields']))
continue;
if (!isset($value['value'])) {
$value['value'] = $key;
}
$value['newrow'] = !isset($value['newrow']) ? false : $value['newrow'];
$value['rowspan'] = !isset($value['rowspan']) ? null : $value['rowspan'];
$value['colspan'] = !isset($value['colspan']) ? null : $value['colspan'];
$resultExp = $this->getSource()->getSqlExp($value, $where);
if (!isset($value['format']) && isset($this->_data['fields'][$key]['format'])) {
$resultExp = $this->_applyFormat($resultExp, $this->_data['fields'][$key]['format']);
} elseif (isset($value['format']) && false !== $value['format']) {
$resultExp = $this->_applyFormat($resultExp, $value['format']);
}
if (isset($value['decorator'])) {
$resultExp = $this->_applyFieldDecorator(array('{{result}}'), array($resultExp), $value['decorator']);
}
$result[$key] = $resultExp;
}
if (!$result)
return array();
$return = array();
foreach ($this->_finalFields as $key => $value) {
$class = $this->getInfo("sqlexp,$key,class") ? ' ' . $this->getInfo("sqlexp,$key,class") : '';
$value = (array_key_exists($key, $result)) ? $result[$key] : '';
$newrow = isset($value['newrow']) ? $value['newrow'] : '';
$rowspan = isset($value['rowspan']) ? $value['rowspan'] : '';
$colspan = isset($value['colspan']) ? $value['colspan'] : '';
$return[] = array('class' => $class,
'value' => $value,
'field' => $key,
'newrow' => $newrow,
'rowspan' => $rowspan,
'colspan' => $colspan);
}
return $return;
}
/**
* Make sure the fields exists on the database, if not remove them from the array
*
* @param array $fields Array of fields to be validated
*
* @return void
*/
protected function _validateFields(array $fields)
{
$hidden = array();
$show = array();
$titles = array();
foreach ($fields as $key => $value) {
if (!isset($value['order']) || $value['order'] == 1) {
if (isset($value['orderField'])) {
$orderFields[$key] = $value['orderField'];
} else {
$orderFields[$key] = $key;
}
}
if (isset($value['title'])) {
$titles[$key] = $value['title'];
} else {
$titles[$key] = ucwords(str_replace('_', ' ', $key));
}
if (isset($this->_data['fields'][$key]['hidden']) && $this->_data['fields'][$key]['hidden'] == 1) {
$hidden[$key] = $key;
} else {
$show[$key] = $key;
}
}
$fieldsFinal = array();
$lastIndex = 1;
$norder = 0;
foreach ($show as $key => $value) {
$value = $this->_data['fields'][$value];
if (isset($value['position']) && (!isset($value['hidden']) || $value['hidden'] == 0)) {
if ($value['position'] === 'last') {
$fieldsFinal[($lastIndex + 100)] = $key;
} elseif ($value['position'] === 'first') {
$fieldsFinal[($lastIndex - 100)] = $key;
} else {
if ($value['position'] === 'next') {
$norder = $lastIndex + 1;
} else {
$norder = (int) $value['position'];
}
if (array_key_exists($norder, $fieldsFinal)) {
for ($i = count($fieldsFinal); $i >= $norder; $i--) {
if (!isset($fieldsFinal[$i]))
continue;
$fieldsFinal[($i + 1)] = $fieldsFinal[$i];
}
$fieldsFinal[$norder] = $key;
}
$fieldsFinal[$norder] = $key;
}
} elseif (!isset($value['hidden']) || $value['hidden'] == 0) {
while (true) {
if (array_key_exists($lastIndex, $fieldsFinal)) {
$lastIndex++;
} else {
break;
}
}
$fieldsFinal[$lastIndex] = $key;
}
}
ksort($fieldsFinal);
foreach ($fieldsFinal as $key => $value) {
if (strlen($value) == 0)
unset($fieldsFinal[$key]);
}
$fieldsFinal = array_values($fieldsFinal);
//Put the hidden fields on the end of the array
foreach ($hidden as $value) {
$fieldsFinal[] = $value;
}
$this->_fields = $fieldsFinal;
$this->_titles = $titles;
$this->_fieldsOrder = $orderFields;
}
/**
* Make sure the filters exists, they are the name from the table field.
* If not, remove them from the array
* If we get an empty array, we then create a new one with all the fields specified
* in $this->_fields method
*
* @return array
*/
protected function _validateFilters()
{
if ($this->getInfo('noFilters') == 1)
return false;
if (is_array($this->_filters) && count($this->_filters) > 0)
return $this->_filters;
return array_combine($this->_fields, $this->_fields);
}
/**
* Checks if there are any filters
*
* @return bool
*/
public function hasFilters()
{
if (count(array_intersect_key(array_combine($this->getFields(), $this->getFields()), $this->_ctrlParams)) > 0)
return true;
return false;
}
/**
* Build user defined filters
*
* @return Bvb_Grid
*/
protected function _buildDefaultFiltersValues()
{
if ($this->_paramsInSession === true) {
if ($this->getParam('noFilters')) {
$this->_sessionParams->filters = null;
}
}
if ((is_array($this->_defaultFilters) || $this->_paramsInSession === true)
&& !$this->hasFilters()
&& !$this->getParam('noFilters')
) {
foreach ($this->_data['fields'] as $key => $value) {
if (!$this->_displayField($key)) {
continue;
}
if ($this->_paramsInSession === true) {
if (isset($this->_sessionParams->filters[$key])) {
if (is_array($this->_sessionParams->filters[$key])) {
foreach ($this->_sessionParams->filters[$key] as $skey => $svalue) {
if (!isset($this->_ctrlParams[$key . $this->getGridId() . '[' . $skey . ']'])) {
$this->_ctrlParams[$key . $this->getGridId() . '[' . $skey . ']'] = $svalue;
}
}
} else {
if (!isset($this->_ctrlParams[$key . $this->getGridId()])) {
$this->_ctrlParams[$key . $this->getGridId()] = $this->_sessionParams->filters[$key];
}
}
continue;
}
}
if (is_array($this->_defaultFilters) && array_key_exists($key, $this->_defaultFilters)) {
$this->_ctrlParams[$key] = $this->_defaultFilters[$key];
}
}
}
return $this;
}
/**
* Deploys
*
* @return Bvb_Grid
*/
public function deploy()
{
if ($this->getSource() === null) {
throw new Bvb_Grid_Exception('Please specify your source');
}
$this->emitEvent('grid.init_deploy', array());
//Disable ajax for CRUD operations
if (!is_null($this->_crud)) {
$this->setAjax(false);
}
$fields = $this->getSource()->buildFields();
$newFields = array_diff(array_keys($fields), array_keys($this->_data['fields']));
foreach ($newFields as $field) {
$this->_data['fields'][$field] = $fields[$field];
}
//Add columns in queue
foreach ($this->_updateColumnQueue as $field => $options) {
$this->updateColumn($field, $options);
}
// apply additional configuration
$this->runConfigCallbacks();
if (($this->getParam('detail') && $this->_deployName == 'table' ) || $this->getParam('delete')
) {
$this->_isDetail = true;
}
if ($this->_isDetail === true && is_array($this->_detailColumns)) {
if (count($this->_detailColumns) > 0) {
$finalColumns = array_intersect($this->_detailColumns, array_keys($this->_data['fields']));
foreach ($this->_data['fields'] as $key => $value) {
if (!in_array($key, $finalColumns)) {
$this->updateColumn($key, array('remove' => 1));
}
}
} else {
foreach ($this->getHiddenFields() as $field) {
$this->updateColumn($field, array('hidden' => false));
}
}
}
if ($this->_isDetail === false && is_array($this->_gridColumns)) {
$finalColumns = array_intersect($this->_gridColumns, array_keys($this->_data['fields']));
foreach ($this->_data['fields'] as $key => $value) {
if (!in_array($key, $finalColumns)) {
$this->updateColumn($key, array('remove' => 1));
}
}
foreach (array_keys($this->_extraColumns) as $value) {
if ($value == 'ZFG_MASS_ACTIONS')
continue;
if (!in_array($value, $this->_gridColumns)) {
unset($this->_extraColumns[$value]);
}
}
}
if ($this->_isDetail == true) {
$result = $this->getSource()->fetchDetail($this->getIdentifierColumnsFromUrl());
if ($result == false) {
$this->_gridSession->message = $this->__('Record Not Found');
$this->_gridSession->_noForm = 1;
$this->_gridSession->correct = 1;
$this->_redirect($this->getUrl(array('comm', 'detail', 'delete')));
}
}
if (count($this->getSource()->getSelectOrder()) == 1 && !$this->getParam('order')) {
$norder = $this->getSource()->getSelectOrder();
if (!$norder instanceof Zend_Db_Expr) {
$this->setParam('order' . $this->getGridId(), $norder[0] . '_' . strtoupper($norder[1]));
}
}
$this->emitEvent('grid.before_filters');
$this->_buildDefaultFiltersValues();
// Validate table fields, make sure they exist...
$this->_validateFields($this->_data['fields']);
// Filters. Not required that every field as filter.
$this->_filters = $this->_validateFilters($this->_filters);
$this->_buildFiltersValues();
if ($this->_isDetail == false) {
$this->_buildQueryOrderAndLimit();
}
if ($this->getParam('noOrder') == 1) {
$this->getSource()->resetOrder();
}
if ( !$this->_deployNeedsData() ) {
$result = array();
$resultCount = 0;
} else {
$result = $this->getSource()->execute();
$resultCount = $this->getSource()->getTotalRecords();
}
$this->_totalRecords = $resultCount;
$this->_result = $result;
$this->_colspan();
if (count($this->getVisibleFields()) == 0) {
throw new Bvb_Grid_Exception('No columns to show');
}
if ($this->getParam('_option') == 'autocomplete' && $this->getParam('_gridId') == $this->getGridId(true)) {
$field = $this->getParam('field');
if (!$this->getField($field)) {
throw new Bvb_Grid_Exception('Field not found');
}
$term = $this->getParam('term');
$specialKeys = array('sqlexp',
':empty',
':isnull',
'isnotnull',
'equal',
'=',
'rege',
'rlike',
'*',
'>=',
'>',
'<>',
'!=',
'<=',
'<',
'in',
'flag',
'||',
'range',
'&',
'and',
'like');
$specialKey = '';
foreach ($specialKeys as $value) {
if (substr($term, 0, strlen($value)) == $value) {
$specialKey = substr($term, 0, strlen($value));
$term = substr($term, strlen($value));
break;
}
}
return $this->getSource()->getAutoCompleteForFilter($term, $field, $specialKey);
}
return $this;
}
/**
* Get details about a column
*
* @param string $column Column name to be returned
*
* @return mixed
*/
protected function _getColumn($column)
{
return isset($this->_data['fields'][$column]) ? $this->_data['fields'][$column] : null;
}
/**
* Convert Object to Array
*
* @param object $data Obejct to be converted to array
*
* @return array
*/
protected function _object2array($data)
{
if (!is_object($data) && !is_array($data))
return $data;
if (is_object($data))
$data = get_object_vars($data);
return array_map(array($this, '_object2array'), $data);
}
/**
* set template locations
*
* @param string $dir Classes Location
* @param string $prefix Classes Prefix
* @param string $type Template Type
*
* @return Bvb_Grid
*/
public function addTemplateDir($dir, $prefix, $type)
{
if (!isset($this->_templates[$type])) {
$this->_templates[$type] = new Zend_Loader_PluginLoader();
}
$this->_templates[$type]->addPrefixPath(trim($prefix, '_'), trim($dir, '/') . '/', $type);
return $this;
}
/**
* Define the template to be used
*
* @param string $template Template Name
* @param string $output Outpute type. It's the deploy class name
* @param array $options Template Options
*
* @return void
*/
public function setTemplate($template, $output = 'table', $options = array())
{
$tmp = $options;
$options['userDefined'] = $tmp;
$class = $this->_templates[$output]->load($template);
if (isset($this->_options['template'][$output][$template])) {
$tpOptions = array_merge($this->_options['template'][$output][$template], $options);
} else {
$tpOptions = $options;
}
$tpInfo = array('colspan' => $this->_colspan,
'charEncoding' => $this->getCharEncoding(),
'name' => $template, 'dir' => $this->_templates[$output]->getClassPath($template),
'class' => $this->_templates[$output]->getClassName($template));
$this->_temp[$output] = new $class();
$this->_temp[$output]->options = array_merge($tpInfo, $tpOptions);
return $this->_temp[$output];
}
/**
* Add multiple columns at once
*
* @return Bvb_Grid
*/
public function updateColumns()
{
$fields = func_get_args();
foreach ($fields as $field) {
if (!$field instanceof Bvb_Grid_Column) {
throw new Bvb_Grid_Exception('Instance of Bvb_Grid_Column must be provided');
}
foreach ($field->getField() as $fieldName => $options) {
$this->updateColumn($fieldName, $options);
}
}
return $this;
}
/**
* Calculate colspan for pagination and top
*
* @return int
*/
protected function _colspan()
{
$row = 0;
$totalFields[$row] = 0;
// add the extra left fields
foreach ($this->_extraColumns as $value) {
if ($value['position'] != 'left') {
continue;
}
$rows = 1;
$cols = 1;
if (isset($value['newrow']) && $value['newrow']) {
$row++;
}
if (isset($value['rowspan']) && $value['rowspan'] !== null) {
$rows = $value['rowspan'];
}
if (isset($value['colspan']) && $value['colspan'] !== null) {
$cols = $value['colspan'];
}
if ($cols < 0) {
$cols = 1;
}
// add the appropriate number of columns for the relevant rows
for ($a = 0; $a < $rows; $a++) {
$totalFields[$row + $a] += $cols;
}
}
// loop through the fields
foreach ($this->_fields as $nf) {
$rows = 1;
$cols = 1;
if (isset($this->_data['fields'][$nf])) {
// skip certain types of fields
$value = $this->_data['fields'][$nf];
if (isset($value['remove']) && $value['remove'] == 1) {
continue;
} elseif (isset($value['hidden']) && $value['hidden'] == 1 && $this->_removeHiddenFields === true) {
continue;
}
if (isset($value['hRow']) && $value['hRow'] == 1) {
continue;
}
if (isset($value['newrow']) && $value['newrow']) {
$row++;
}
if (isset($value['rowspan']) && $value['rowspan'] !== null) {
$rows = $value['rowspan'];
}
if (isset($value['colspan']) && $value['colspan'] !== null) {
$cols = $value['colspan'];
}
if ($cols < 0) {
$cols = 1;
}
}
// add the appropriate number of columns for the relevant rows
for ($a = 0; $a < $rows; $a++) {
if (!isset($totalFields[$row + $a])) {
$totalFields[$row + $a] = 0;
}
$totalFields[$row + $a] += $cols;
}
}
// add the extra right fields
foreach ($this->_extraColumns as $value) {
if ($value['position'] != 'right') {
continue;
}
$rows = 1;
$cols = 1;
if (isset($value['newrow']) && $value['newrow']) {
$row++;
}
if (isset($value['rowspan']) && $value['rowspan'] !== null) {
$rows = $value['rowspan'];
}
if (isset($value['colspan']) && $value['colspan'] !== null) {
$cols = $value['colspan'];
}
if ($cols < 0) {
$cols = 1;
}
// add the appropriate number of columns for the relevant rows
for ($a = 0; $a < $rows; $a++) {
$totalFields[$row + $a] += $cols;
}
}
if ($this->_allowDelete == 1) {
$totalFields[$row]++;
}
if ($this->_allowEdit == 1) {
$totalFields[$row]++;
}
if (is_array($this->_detailColumns) && $this->_isDetail == false) {
$totalFields[$row]++;
}
if ($this->_massActions->hasMassActions()) {
$totalFields[$row]++;
}
$this->_colspan = max($totalFields);
return $this->_colspan;
}
/**
* Returns a field and its options
*
* @param string $field Field Name
*
* @return mixed
*/
public function getField($field)
{
return isset($this->_data['fields'][$field]) ? $this->_data['fields'][$field] : false;
}
/**
* Return fields list.
* Optional param returns also fields options
*
* @param bool $returnOptions If grid should return all options or only fields names
*
* @return array
*/
public function getFields($returnOptions = false)
{
if (false !== $returnOptions) {
return $this->_data['fields'];
}
return array_keys($this->_data['fields']);
}
/**
* Returns all hidden fields
*
* @return array
*/
public function getHiddenFields()
{
$returnFields = array();
foreach ($this->getFields() as $value) {
if (!$this->_displayField($value))
$returnFields[] = $value;
}
return $returnFields;
}
/**
* Returns all visible fields
*
* @return array
*/
public function getVisibleFields()
{
$returnFields = array();
foreach ($this->getFields() as $value) {
if ($this->_displayField($value))
$returnFields[] = $value;
}
return $returnFields;
}
/**
* Add filters
*
* @param Bvb_Grid_Filters $filters Filters object to be added to the grid
*
* @return Bvb_Grid
*/
public function addFilters(Bvb_Grid_Filters $filters)
{
$filters = $filters->getFilters();
$this->emitEvent('grid.add_extra_filters', array('filters' => $filters));
foreach ($filters as $key => $value) {
if (isset($filters[$key]['callback'])) {
$filters[$key]['callback'] = $value['callback'];
}
if (isset($filters[$key]['transform'])) {
$filters[$key]['transform'] = $value['transform'];
}
}
$this->_filters = array_merge($this->_filters, $filters);
foreach ($filters as $key => $filter) {
if (isset($filter['searchType'])) {
$this->updateColumn($key, array('searchType' => $filter['searchType']));
}
if (isset($filter['searchTypeFixed'])) {
$this->updateColumn($key, array('searchTypeFixed' => $filter['searchTypeFixed']));
}
if (isset($filter['search'])) {
$this->updateColumn($key, array('search' => $filter['search']));
}
}
return $this;
}
/**
* Clears existing filters
*
* @return Bvb_Grid
*/
public function clearFilters()
{
$this->_filters = array();
return $this;
}
/**
* Returns current filters
*
* @return array
*/
public function getFilters()
{
return $this->_filters;
}
/**
* Returns a specific filter
*
* @param string $filter
* @return array|false
*/
public function getFilter($filter)
{
return isset($this->_filters[$filter]) ? $this->_filters[$filter] : false;
}
/**
* Add filters removing pre-existing ones
*
* @param Bvb_Grid_Filters $filters
* @return Bvb_Grid
*/
public function setFilters($filters)
{
$this->_filters = array();
$this->addFilters($filters);
return $this;
}
/**
* Add extra columns
*
* @return Bvb_Grid
*/
public function addExtraColumns($columns = array())
{
static $order = 10;
if (is_array($columns)) {
$extraColumns = $columns;
} else {
$extraColumns = func_get_args();
}
if (count($extraColumns) == 0) {
throw new Bvb_Grid_Exception('No Columns To Add');
}
$this->emitEvent('grid.add_extra_columns', array('columns' => $extraColumns));
foreach ($extraColumns as $value) {
if (!$value instanceof Bvb_Grid_Extra_Column) {
$value = new Bvb_Grid_Extra_Column($value['name'], $value);
#throw new Bvb_Grid_Exception($value . ' must be a instance of Bvb_Grid_Extra_Column');
}
if (!$value->getOption('name') || !is_string($value->getOption('name'))) {
throw new Bvb_Grid_Exception('You need to define the column name');
}
if ($value->getOption('title') && !is_string($value->getOption('title'))) {
throw new Bvb_Grid_Exception('title option must be a string');
}
if (!$value->getOption('position') || !in_array($value->getOption('position'), array('left', 'right'))) {
throw new Bvb_Grid_Exception('Please define column position (left|right)');
}
if (!$value->getOption('order')) {
$order++;
$value->setOption('order', $order);
}
$this->_extraColumns[$value->getOption('name')] = $value->getColumn();
}
return $this;
}
/**
* Returns a extra column
*
* @param string $name
* @return mixed
*/
public function getExtraColumn($name)
{
return isset($this->_extraColumns[$name]) ? $this->_extraColumns[$name] : null;
}
/**
* Adds a extra colum to the grid
*
* @param array $column
* @return Bvb_Grid
*/
public function addExtraColumn($column = array())
{
$column = array($column);
$this->addExtraColumns($column);
return $this;
}
/**
* Clears Current Extra Columns
*
* @return Bvb_Grid
*/
public function clearExtraColumns()
{
$this->_extraColumns = array();
return $this;
}
/**
* Adds new extra columns
*
* @param mixed $columns Columns to add
* @return Bvb_Grid
*/
public function setExtraColumns($columns = array())
{
$this->_extraColumns = array();
$this->addExtraColumns($columns);
return $this;
}
/**
* Returns current extra columns
*
* @return array
*/
public function getExtraColumns()
{
return $this->_extraColumns;
}
/**
* Returns the grid version
*
* @return string
* @static
*/
public static function getVersion()
{
return self::VERSION;
}
/**
* Return number records found
*
* @return integer
*/
public function getTotalRecords()
{
return (int) $this->_totalRecords;
}
/**
* Automates export functionality
*
* @param string $defaultClass
* @param mixed $options
* @param mixed $id
* @param array|array $classCallbacks key should be lowercase, functions to call once before deploy() or ajax()
* @param array|boolean $requestParams request parameters will be used if FALSE
* @static
*
* @return Bvb_Grid
*/
public static function factory($defaultClass = 'Table', $options = array(), $id = '', $classCallbacks = array(), $requestParams = false)
{
self::initDeployClass();
if (!is_string($id)) {
$id = '';
}
try {
$defaultClass = self::loadDeployClass($defaultClass);
} catch (Zend_Loader_PluginLoader_Exception $e) {
// let's try if the class is not loaded already
if (!class_exists($defaultClass)) {
throw $e;
}
}
if (false === $requestParams) {
// use request parameters
$requestParams = Zend_Controller_Front::getInstance()->getRequest()->getParams();
}
if ($options instanceof Zend_Config) {
$options = $options->toArray();
}
// use this as request parameters
if (!isset($options['grid'])) {
$options['grid'] = array('requestParams' => $requestParams);
} else {
$options['grid']['requestParams'] = $requestParams;
}
// handle _exportTo parameter compatible with calling with grid id and without
if (isset($requestParams['_exportTo' . $id])) {
$exportTo = $requestParams['_exportTo' . $id];
} elseif (isset($requestParams['_exportTo'])) {
$exportTo = $requestParams['_exportTo'];
} else {
$exportTo = false;
}
if (false === $exportTo) {
// return instance of the main Bvb object, because this is not and export request
$grid = new $defaultClass($options);
$lClass = $defaultClass;
} else {
$lClass = strtolower($exportTo);
// support translating of parameters specifig for the export initiator class
if (isset($requestParams['_exportFrom'])) {
// TODO support translating of parameters specifig for the export initiator class
$requestParams = $requestParams;
}
// now we need to find and load the right Bvb deploy class
// TODO support user defined classes
$className = self::loadDeployClass($exportTo);
if (Zend_Loader_Autoloader::autoload($className)) {
$grid = new $className($options);
} else {
$grid = new $defaultClass($options);
$lClass = $defaultClass;
}
}
// add the powerfull configuration callback function
if (isset($classCallbacks[$lClass])) {
$grid->_configCallbacks = $classCallbacks[$lClass];
}
if (is_string($id)) {
$grid->setGridId($id);
}
return $grid;
}
/**
* Runs configuration callbacks
*
* @return void
*/
public function runConfigCallbacks()
{
if (!$this->_runCallbacks) {
// makes shure that config callbacks will be used once
return;
}
$this->_runCallbacks = false;
if (!is_array($this->_configCallbacks)) {
call_user_func($this->_configCallbacks, $this);
} elseif (count($this->_configCallbacks) == 0) {
// no callback
return;
} elseif (count($this->_configCallbacks) > 1 && is_array($this->_configCallbacks[0])) {
die("multi");
// TODO maybe fix
// ordered list of callback functions defined
foreach ($this->_configCallbacks as $func) {
}
} else {
// only one callback function defined
call_user_func($this->_configCallbacks, $this);
}
// run it only once
$this->_configCallbacks = array();
}
/**
* Build list of exports with options
*
* Options:
* caption - mandatory
* img - (default null)
* cssClass - (default ui-icon-extlink)
* newWindow - (default true)
* url - (default actual url)
* onClick - (default null)
* _class - (reserved, used internaly)
*
* @return array
*/
public function getExports()
{
$res = array();
foreach ($this->_export as $name => $defs) {
if (!is_array($defs)) {
// only export name is passed, we need to get default option
$name = $defs;
$className = 'Bvb_Grid_Deploy_' . ucfirst($name); // TODO support user defined classes
if (Zend_Loader_Autoloader::autoload($className) && method_exists($className, 'getExportDefaults')) {
// learn the defualt values
$defs = call_user_func(array($className, 'getExportDefaults'));
} else {
// there are no defaults, we need at least some caption
$defs = array('caption' => $name);
}
$defs['_class'] = $className;
}
$res[$name] = $defs;
}
return $res;
}
/**
* This is useful if the deploy class has no intention of using hidden fields
*
* @param bool $value Field Name
*
* @return Bvb_Grid
*/
protected function _setRemoveHiddenFields($value)
{
$this->_removeHiddenFields = (bool) $value;
return $this;
}
/**
* Adds more options to the grid
*
* @param mixed $options Associative array of options to be applied
*
* @return Bvb_Grid
*/
public function updateOptions($options)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} else if (!is_array($options)) {
throw new Bvb_Grid_Exception('options must be an instance from Zend_Config or an array');
}
$this->_options = array_merge($this->_options, $options);
return $this;
}
/**
* Return current config options
*
* @return array
*/
public function getOptions()
{
return $this->_options;
}
/**
* Defines options to the grid
*
* @param array $options Associative array of options to be applied
*
* @return Bvb_Grid
*/
public function setOptions(array $options)
{
$this->_options = $options;
return $this;
}
/**
* Add options to the grid
*
* @param array $options Associative array of options to be applied
*
* @return Bvb_Grid
*/
public function addOptions(array $options)
{
$this->_options = array_merge_recursive($options, $this->_options);
return $this;
}
/**
* Apply the options to the fields
*
* @return void
*/
protected function _applyOptionsToFields()
{
if (isset($this->_options['fields']) && is_array($this->_options['fields'])) {
foreach ($this->_options['fields'] as $field => $options) {
if (isset($options['format']['function'])) {
if (!isset($options['format']['params'])) {
$options['format']['params'] = array();
}
$options['format'] = array($options['format']['function'], $options['format']['params']);
}
if (isset($options['callback'])) {
if (!isset($options['callback']['params'])) {
$options['callback']['params'] = array();
}
if (isset($options['callback']['function']) && isset($options['callback']['class'])) {
$options['callback'] = array('function' => array($options['callback']['class'],
$options['callback']['function']),
'params' => $options['callback']['params']);
} else {
$options['callback'] = array('function' => $options['callback']['function'],
'params' => $options['callback']['params']);
}
}
$this->updateColumn($field, $options);
}
}
if (isset($this->_options['filters']) && is_array($this->_options['filters'])) {
$filters = new Bvb_Grid_Filters();
foreach ($this->_options['filters'] as $column => $filter) {
if (isset($filter['values']) && is_array($filter['values'])) {
$filters->addFilter($column, array('values' => $filter['values']));
}
if (isset($filter['distinct']) && is_array($filter['distinct'])) {
$filters->addFilter($column, array('distinct' => array('name' => $filter['distinct']['name'], 'field' => $filter['distinct']['field'])));
}
}
$this->addFilters($filters);
}
$deploy = explode('_', get_class($this));
$name = strtolower(end($deploy));
if (isset($this->_options['deploy'][$name]) && is_array($this->_options['deploy'][$name])) {
if (method_exists($this, '_applyConfigOptions')) {
$this->_applyConfigOptions($this->_options['deploy'][$name], true);
} else {
$this->_deploy = $this->_options['deploy'][$name];
}
}
if (isset($this->_options['template'][$name]) && is_array($this->_options['template'][$name])) {
$this->addTemplateParams($this->_options['template'][$name]);
}
if (isset($this->_options['grid']['formatter'])) {
$this->_options['grid']['formatter'] = (array) $this->_options['grid']['formatter'];
foreach ($this->_options['grid']['formatter'] as $formatter) {
$temp = $formatter;
$temp = str_replace('_', '/', $temp);
$this->addFormatterDir($temp, $formatter);
}
}
if (isset($this->_options['grid']['eventsPrefix'])) {
$this->setEventsPrefix($this->_options['grid']['eventsPrefix']);
}
if (isset($this->_options['grid']['recordsPerPage'])) {
$this->setRecordsPerPage($this->_options['grid']['recordsPerPage']);
}
if (isset($this->_options['grid']['modRewrite'])) {
self::useModRewrite($this->_options['grid']['modRewrite']);
}
if (isset($this->_options['grid']['paginationInterval'])) {
$this->setPaginationInterval($this->_options['grid']['paginationInterval']);
}
}
/**
* Sets the grid id, to allow multiples instances per page
*
* @param string $id Grid to be used in grid
*
* @return Bvb_Grid
*/
public function setGridId($id)
{
$this->_gridId = trim(preg_replace("/[^a-zA-Z0-9_]/", '_', $id), '_');
return $this;
}
/**
* Returns the current id.
*
* ""=>emty string is a valid value
*
* @param bool $forceId If we should force an id to be returned in case no one is set
*
* @return string
*/
public function getGridId($forceId = false)
{
if ($forceId === true && strlen($this->_gridId) == 0) {
return $this->getRequest()->getActionName()
. '_' . $this->getRequest()->getControllerName()
. '_' . $this->getRequest()->getModuleName();
}
return $this->_gridId;
}
/**
* Set user defined params for templates.
*
* @param array $options Associative array o options to pass to template
*
* @return Bvb_Grid
*/
public function setTemplateParams(array $options)
{
$this->_templateParams = $options;
return $this;
}
/**
* Set user defined params for templates.
*
* @param string $name Name of the variable
* @param mixed $value value of the variable
*
* @return Bvb_Grid
*/
public function addTemplateParam($name, $value)
{
$this->_templateParams[$name] = $value;
return $this;
}
/**
* Adds user defined params for templates.
*
* @param array $options Options to be passed to the template
*
* @return Bvb_Grid
*/
public function addTemplateParams(array $options)
{
$this->_templateParams = array_merge($this->_templateParams, $options);
return $this;
}
/**
* Returns template info defined by the user
*
* @return array
*/
public function getTemplateParams()
{
return $this->_templateParams;
}
/**
* Reset options for column
*
* @param string $column Column which should have options reseted
*
* @return Bvb_Grid
*/
public function resetColumn($column)
{
$support = array();
$support['title'] = isset($this->_data['fields']['title']) ? $this->_data['fields']['title'] : '';
$support['field'] = isset($this->_data['fields']['field']) ? $this->_data['fields']['field'] : '';
$this->_data['fields'][$column] = $support;
return $this;
}
/**
* Reset options for several columns
*
* @param array $columns Columns which should have options reseted
*
* @return Bvb_Grid
*/
public function resetColumns(array $columns)
{
foreach ($columns as $column) {
$this->resetColumn($column);
}
return $this;
}
/**
* Defines which columns will be available to user
*
* @param array $columns Columns to be showed
*
* @return Bvb_Grid
*/
public function setGridColumns(array $columns)
{
$this->_gridColumns = $columns;
return $this;
}
/**
* Adds more columns to be showed
*
* @param array $columns Columns to be showed
*
* @return Bvb_Grid
*/
public function addGridColumns(array $columns)
{
$this->_gridColumns = array_merge($this->_gridColumns, $columns);
return $this;
}
/**
* Defines which columns will be available on detail view
*
* @param array $columns Columns to be showed
*
* @return Bvb_Grid
*/
public function setDetailColumns(array $columns = array())
{
$this->_detailColumns = $columns;
return $this;
}
/**
* Adds more columns that will be available on detail view
*
* @param array $columns Array of columns to be showed within detail view
*
* @return Bvb_Grid
*/
public function addDetailColumns(array $columns)
{
$this->_detailColumns = array_merge($this->_detailColumns, $columns);
return $this;
}
/**
* Get the list of primary keys from the URL
*
* @return array
*/
public function getIdentifierColumnsFromUrl()
{
$par = '';
if ($this->getParam('edit')) {
$par = $this->getParam('edit');
} elseif ($this->getParam('delete')) {
$par = $this->getParam('delete');
} elseif ($this->getParam('detail')) {
$par = $this->getParam('detail');
}
if (strlen($par) == 0)
return array();
$par = explode('-', $par);
$primaryKeys = $this->getSource()->getIdentifierColumns($this->_data['table']);
if (count($par) != count($primaryKeys)) {
return array();
}
$primaryKeys = array_combine($primaryKeys, $par);
return $primaryKeys;
}
/**
* Returns request param without search for grid id
*
* @param string $param Param Name
* @param mixed $default Default value to be returned if param does not exists
*
* @return mixed
*/
public function getRequestParamClean($param, $default=null)
{
$result = $this->getRequest()->getParam($param);
return is_null($result) ? $default : $result;
}
/**
* Returns request param for current grid id
*
* @param string $param Param Name
* @param mixed $default Default value to be returned if param does not exists
*
* @return mixed
*/
public function getRequestParam($param, $default=null)
{
$param = $param . $this->getGridId();
$result = $this->getRequest()->getParam($param);
return is_null($result) ? $default : $result;
}
/**
* Get a param from the $this->_ctrlParams appending the grid id
*
* @param string $param Param Name
* @param mixed $default Default value to be returned if param does not exists
*
* @return mixed
*/
public function getParam($param, $default=null)
{
if(array_key_exists($param, $this->_externalFilters))
{
return isset($this->_ctrlParams[$param]) ? $this->_ctrlParams[$param] : $default;
}
$param = $param . $this->getGridId();
return isset($this->_ctrlParams[$param]) ? $this->_ctrlParams[$param] : $default;
}
/**
* Returns all params received from Zend_Controller
*
* @return array
*/
public function getParams()
{
return $this->_ctrlParams;
}
/**
* Redirects a user to a give URL and exits
*
* @param string $url URL to redirect
* @param int $code URL Response code
*
* @return void
*/
protected function _redirect($url, $code = 302)
{
$response = $this->getResponse();
$response->setRedirect($url, $code);
$response->sendResponse();
die();
}
/**
* Set a param to be used by controller.
*
* @param string $param Param Name
* @param mixed $value Param value
*
* @return Bvb_Grid
*/
public function setParam($param, $value)
{
$this->_ctrlParams[$param] = $value;
return $this;
}
/**
* Remove a param
*
* @param string $param Param Name
*
* @return Bvb_Grid
*/
public function clearParam($param)
{
unset($this->_ctrlParams[$param]);
return $this;
}
/**
* Unsets all params received from controller
*
* @return Bvb_Grid
*/
public function clearParams()
{
$this->_ctrlParams = array();
return $this;
}
/**
* Defines a new set of params
*
* @param array $params Associative array of params to use
*
* @return Bvb_Grid
*/
public function setParams(array $params)
{
$this->_ctrlParams = $params;
return $this;
}
/**
* Add one more para to the grid
*
* @param string $key Param name
* @param string $value Param Value
*
* @return Bvb_Grid
*/
public function addParam($key, $value)
{
$this->_ctrlParams[$key] = $value;
return $this;
}
/**
* Use this method to add more params to the grid.
*
* @param array $params Associative array of params to be added
*
* @return Bvb_Grid
*/
public function addParams(array $params)
{
$this->_ctrlParams = array_merge($this->_ctrlParams, $params);
return $this;
}
/**
* Defines which export options are available
* Ex: array('word','pdf');
*
* @param array $export Array of key/pairs to be available when exporting
*
* @return Bvb_Grid
*/
public function setExport(array $export)
{
$this->_export = $export;
return $this;
}
/**
* Adds a new export option
*
* @param string $name Deploy classe name to be available when exporting
* @param array $options Options to be applyied
*
* @return Bvb_Grid
*/
public function addExport($name, $options)
{
$this->_export[$name] = $options;
return $this;
}
/**
* Returns the currently setted export methods
*
* @return array
*/
public function getExport()
{
return $this->_export;
}
/**
* Defines SQL expressions
*
* @param array $exp Array of experessions to be built
*
* @return Bvb_Grid
*/
public function setSqlExp(array $exp)
{
$this->_info['sqlexp'] = $exp;
return $this;
}
/**
* Defines the route name to be applied
*
* @param string $url route name
*
* @return Bvb_Grid
*/
public function setRoutename($name)
{
$this->_routeName = $name;
return $this;
}
/**
* Returns the current route name
*
* @return string
*/
public function getRouteName()
{
if (null === $this->_routeName) {
$this->_routeName = $this->getController()->getRouter()->getCurrentRouteName();
}
return $this->_routeName;
}
/**
* Loads the filter to be rendered
*
* @param mixed $render Type of render to be used
*
* @return mixed
*/
public function loadFilterRender($render)
{
if (is_array($render)) {
$toRender = key($render);
} else {
$toRender = $render;
}
$renderExists = $this->_filtersRenders->getPaths();
$renderInfo = 'Bvb_Grid_Render_' . ucfirst($this->_deployName) . '_' . ucfirst($toRender);
if (!array_key_exists($renderInfo, $renderExists)) {
$this->addFiltersRenderDir('Bvb/Grid/Filters/Render/Table', 'Bvb_Grid_Filters_Render_Table');
}
$classname = $this->_filtersRenders->load(ucfirst($toRender));
if (is_array($render)) {
$class = new $classname($render[$toRender]);
} else {
$class = new $classname();
}
if (!$class instanceof Bvb_Grid_Filters_Render_RenderInterface) {
throw new Bvb_Grid_Exception("$classname must implement Bvb_Grid_Filters_Render_RenderInterface");
}
$class->setGridId($this->getGridId());
return $class;
}
/**
* Adds a new dir to check for filters
*
* @param string $dir Class Name
* @param string $prefix Dir where classes are located
*
* @return Bvb_Grid
*/
public function addFiltersRenderDir($dir, $prefix)
{
$this->_filtersRenders->addPrefixPath(trim($prefix, '_'), trim($dir, '/') . '/');
return $this;
}
/**
* Checks if the active request is a export
*
* @return bool
*/
public function isExport()
{
return in_array($this->getParam('_exportTo'), $this->_export);
}
/**
* Returns the select object from source
*
* @return Bvb_Grid_Source_SourceInterface
*/
public function getSelect()
{
return $this->getSource()->getSelectObject();
}
/**
* Adds extra rows to the grid.
*
* @param Bvb_Grid_Extra_Rows $rows Rowset of columns to add
*
* @return Bvb_Grid_Deploy_Table
*/
public function addExtraRows(Bvb_Grid_Extra_Rows $rows)
{
$this->emitEvent('grid.add_extra_rows', array('rows' => $rows));
$rows = $this->_object2array($rows);
$this->_extraRows = array_merge($this->_extraRows, $rows['_rows']);
return $this;
}
/**
* Adds a new external filters
*
* @param string $fieldId Field id to be used
* @param string $callback Callback to be called. Will receive. $id,$value,$select
*
* @throws Bvb_Grid_Exception
* @return Bvb_Grid
*/
public function addExternalFilter($fieldId, $callback)
{
if (!is_callable($callback)) {
throw new Bvb_Grid_Exception($callback . ' not callable');
}
$this->_externalFilters[$fieldId] = $callback;
return $this;
}
/**
* Clears all external filters
*
* @return Bvb_Grid
*/
public function clearExternalFilters()
{
$this->_externalFilters = array();
return $this;
}
/**
* Removes a specified filter
*
* @param string $fieldId Field to be removed
*
* @return Bvb_Grid
*/
public function removeExternalFilter($fieldId)
{
if (isset($this->_externalFilters[$fieldId])) {
unset($this->_externalFilters[$fieldId]);
}
return $this;
}
/**
* Defines if filters should be showned in export
*
* @param bool $show If we should show filters or not when exporting
*
* @return Bvb_Grid
*/
public function setShowFiltersInExport($show)
{
$this->_showFiltersInExport = $show;
return $this;
}
/**
* Whetever to save or not in session filters and order
* This is based on gridId, if not provided, action_controller_module
*
* @param bool $status The status to be setted
*
* @return Bvb_Grid
*/
public function saveParamsInSession($status)
{
$this->_paramsInSession = (bool) $status;
return $this;
}
/**
* Defines options for deployment
*
* @param array $options Asociative array with options for deploy
*
* @return Bvb_Grid
*/
public function setDeployOptions(array $options)
{
foreach ($options as $option => $value) {
$this->setDeployOption($option, $value);
}
return $this;
}
/**
* Defines option for deployment
*
* @param string $option Options name
* @param string $value Option value
*
* @return Bvb_Grid
*/
public function setDeployOption($option, $value)
{
$this->_deploy[$option] = $value;
return $this;
}
/**
* Retrieve a value and return $default if there is no element set.
*
* @param string $name The key name to de fetched
* @param mixed $default The value to be returned if key does not exist
*
* @return mixed
*/
public function getDeployOption($name, $default = null)
{
return (array_key_exists($name, $this->_deploy)) ? $this->_deploy[$name] : $default;
}
/**
* Reset Deploy Options
*
* @return Bvb_Grid
*/
public function clearDeployOptions()
{
$this->_deploy = array();
return $this;
}
/**
* retrieve deploy options
*
* @return array
*/
public function getDeployOptions()
{
return $this->_deploy;
}
/**
* Checks if the user has the right to export for the defined format
*
* @throws Bvb_Grid_Exception
*
* @return void
*/
public function checkExportRights()
{
if (!in_array($this->_deployName, $this->_export) && !array_key_exists($this->_deployName, $this->_export)) {
throw new Bvb_Grid_Exception($this->__("You don't have permission to export the results to this format"));
}
}
/**
* Build an array based on the given key name (why this never made it to PHP core I'll never know).
*
* @param array $array Array to be used
* @param string $key Key to be
*
* @see http://www.php.net/manual/en/function.array-map.php#96269
*
* @return array
*/
public function arrayPluck($array, $key = 'value')
{
if (!is_array($array))
return array();
$result = array();
foreach ($array as $row) {
if (array_key_exists($key, $row))
$result[] = $row[$key];
}
return $result;
}
/**
* Defines the default grid configuration
*
* @param Zend_Config|array $options Config Options
*
* @throws Bvb_Grid_Exception
* @static
*
* @return void
*/
public static function setDefaultConfig($options)
{
if ($options instanceof Zend_Config) {
$options = $options->toArray();
} elseif (!is_array($options)) {
throw new Bvb_Grid_Exception('options must be an instance from Zend_Config or an array');
}
self::$_defaultConfig = $options;
}
/**
* Returns the current default configuration
*
* @return array
*/
public static function getDefaultConfig()
{
return self::$_defaultConfig;
}
/**
* Reutrns field alias
*
* @param string $field Field alias
*
* @return string
*/
public function getFieldAlias($field)
{
foreach ($this->getFields(true) as $alias => $value) {
if ($value['field'] == $field)
return $alias;
}
}
/**
* Returns a url to be used to get a list of possible values from DB.
*
* @param string $field A valid field from query
*
* @return string
*/
public function getAutoCompleteUrlForFilter($field)
{
if (!$this->getField($field)) {
throw new Bvb_Grid_Exception('Field not found');
}
return $this->getUrl(array('order')) . '/_gridId/' . $this->getGridId(true) . '/field/' . $field . '/_option/autocomplete';
}
/**
* Sets dispatcher instance
*
* @param Bvb_Grid_Event_Dispatcher $dispatcher Dispatcher instance
* @return Bvb_Grid
*/
public function setEventDispatcher(Bvb_Grid_Event_Dispatcher $dispatcher)
{
$this->_eventDispatcher = $dispatcher;
return $this;
}
/**
* Gets dispatcher instance
*
* @return Bvb_Grid_Event_Dispatcher $dispatcher Dispatcher instance
*/
public function getEventDispatcher()
{
return $this->_eventDispatcher;
}
public function setMassActions(Bvb_Grid_Mass_Actions $actions)
{
$this->emitEvent('grid.set_mass_actions', array('source' => $actions));
$this->_massActions = $actions;
return $this;
}
/**
* Returns Mass Actions instance
*
* @return Bvb_Grid_Mass_Actions
*/
public function getMassActions()
{
return $this->_massActions;
}
/**
* Returns mass actions decorator so the deploy class can build
* the extra column
*
* @return string
*/
protected function _getMassActionsDecorator()
{
if ($this->getMassActions()->getDecorator())
return $this->getMassActions()->getDecorator();
$fieldIdentifier = $this->getSource()->getIdentifierColumns($this->_data['table']);
if (count($this->getMassActions()->getFields()) == 0 && count($fieldIdentifier) == 0) {
throw new Bvb_Grid_Exception('No primary key defined in table. Mass actions not available');
}
if (count($this->getMassActions()->getFields()) == 0) {
$pk = '';
foreach ($fieldIdentifier as $value) {
$aux = explode('.', $value);
$pk .= end($aux) . '-';
}
$pk = rtrim($pk, $this->getMassActions()->getMultipleFieldsSeparator());
$pk = explode($this->getMassActions()->getMultipleFieldsSeparator(), $pk);
}
$pk = "{{" . implode('}}' . $this->getMassActions()->getMultipleFieldsSeparator() . '{{', $pk) . "}}";
$this->getMassActions()->setDecorator($pk);
return $this->getMassActions()->getDecorator();
}
/**
* Sets response object
*
* @param Zend_Controller_Response_Abstract $response
* @return Bvb_Grid
*/
public function setResponse(Zend_Controller_Response_Abstract $response)
{
$this->_response = $response;
return $this;
}
/**
* Returns reponse instance
*
* @return Zend_Controller_Response_Abstract
*/
public function getResponse()
{
if (!isset($this->_response)) {
$this->_response = Zend_Controller_Front::getInstance()->getResponse();
}
return $this->_response;
}
/**
* Regists a new observer
*
* @param string $event Event name
* @param int $event Priority Number
* @param calable $callback Callback to be called
*
* @return Bvb_Grid
*/
public function listenEvent($event, $callback, $priority = 10)
{
Bvb_Grid_Event_Dispatcher::getInstance()->connect($event, $callback, $priority);
return $this;
}
/**
* If we should use mod_write to create URL's
*
* @param bool $modRewrite
* @return Bvb_Grid
*/
public static function useModRewrite($modRewrite)
{
self::$_modRewrite = (bool) $modRewrite;
}
/**
* Get usage of mod_rewrite
*
* @return bool
*/
public static function getUseModRewrite()
{
return self::$_modRewrite;
}
/**
* Defines the prefix to be used in all events
*
* @param string $prefix
* @return Bvb_Grid
*/
public function setEventsPrefix($prefix)
{
$this->_eventsPrefix = (string) $prefix;
return $this;
}
/**
* Returns current event prefix.
*
* @return string/null
*/
public function getEventsPrefix()
{
return $this->_eventsPrefix;
}
/**
* Proxy for emiting events
*
* @param string $name
* @param array $params
* @param object $subject
*/
public function emitEvent($name, $params = array(), $subject=null)
{
if ($subject === null) {
$subject = $this;
}
$event = new Bvb_Grid_Event($name, $subject, $params);
$this->_eventDispatcher->emit($event);
if ($this->getEventsPrefix()) {
$event = new Bvb_Grid_Event($this->getEventsPrefix() . $name, $subject, $params);
$this->_eventDispatcher->emit($event);
}
}
/**
* Adds the default deploy classes dir location
*/
public static function initDeployClass()
{
self::$_deployClassesDir = new Zend_Loader_PluginLoader();
self::$_deployClassesDir->addPrefixPath('Bvb_Grid_Deploy', 'Bvb/Grid/Deploy/');
}
/**
* Adds a new deploy class dir to be loaded
*
* @param string $dir
* @param string $prefix
*/
public static function addDeployPrefixPath($dir, $prefix)
{
self::$_deployClassesDir->addPrefixPath(trim($prefix, '_'), trim($dir, '/') . '/');
}
/**
* Loads a deploy class
*
* @param string $class
*
* @return Bvb_Grid
*/
public static function loadDeployClass($class)
{
return self::$_deployClassesDir->load($class);
}
/**
* Returns current deploy paths
*
* @return mixed
*/
public static function getDeployPrefixPaths()
{
return self::$_deployClassesDir;
}
/**
* In some cases we don't need to execute costly query on data source on grid deployment
*
* @return bool
*/
protected function _deployNeedsData()
{
return true;
}
}
|