Your IP : 10.10.0.253


Current Path : /var/www/administrator/components/com_contactpush/classes/model/
Upload File :
Current File : /var/www/administrator/components/com_contactpush/classes/model/orm.php

<?php
/**                               ______________________________________________
*                          o O   |                                              |
*                 (((((  o      <    Generated with Cook Self Service  V3.1     |
*                ( o o )         |______________________________________________|
* --------oOOO-----(_)-----OOOo---------------------------------- www.j-cook.pro --- +
* @version		1.0.0
* @package		Contact Push
* @subpackage	Contact Push
* @copyright	Netamity 2017
* @author		Andy Hickey - www.netamity.com - andy@netamity.com
* @license		GPL V2+
*
*             .oooO  Oooo.
*             (   )  (   )
* -------------\ (----) /----------------------------------------------------------- +
*               \_)  (_/
*/

// no direct access
defined('_JEXEC') or die('Restricted access');



/**
* ORM Class for Contactpush.
*
* @package	Contactpush
* @subpackage	Class
*/
class ContactpushCkClassModelOrm
{
	/**
	* Database.
	*
	* @var JDatabase
	*/
	protected $_db;

	/**
	* Model where ORM applies.
	*
	* @var JModel
	*/
	protected $model;

	/**
	* Constructor.
	*
	* @access	public
	* @param	JModel	$model	Model where ORM applies.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function __construct($model)
	{
		$this->model = $model;
		$this->_db = JFactory::getDbo();
	}

	/**
	* Filter access (publish + author + accesslevel).
	*
	* @access	public
	* @param	string	$tableField	namespace table.
	* @param	array	$config	Access Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function access($tableField, $config)
	{
		$wherePublished = $allowAuthor = $whereAccess = null;


		$acl = ContactpushHelper::getActions();

		// ACCESS - View Level Access
		if (isset($config['access']))
		{
			$keyAccess = $config['access'];

			$accessNamespace = $tableField . '.' . $keyAccess;
			$accessFieldAlias = static::tableFieldAlias($accessNamespace);

			$this->select($accessNamespace);

			$whereAccess = '1';
			if (!$this->model->canAdmin())
			{
			    $groups	= implode(',', JFactory::getUser()->getAuthorisedViewLevels());
				$whereAccess = $accessFieldAlias . ' IN ('.$groups.')';
			}
		}


		// AUTHOR - Allow the author in some cases
		if (isset($config['author']))
		{
			$keyAuthor = $config['author'];

			$authorNamespace = $tableField . '.' . $keyAuthor;
			$authorFieldAlias = static::tableFieldAlias($authorNamespace);

			$this->select($authorNamespace);

			$allowAuthor = '0';
			// Allow the author to see its own unpublished/archived/trashed items
			if ($acl->get('core.edit.own') || $acl->get('core.view.own') || $acl->get('core.delete.own'))
			{
				$allowAuthor = $authorFieldAlias . ' = ' . (int)JFactory::getUser()->get('id');
			}

			// Do not apply filter
			if ($allowAuthor == '0')
				$allowAuthor = null;
		}


		if (isset($config['publish']))
		{
			$keyPublished = $config['publish'];

			$publishedNamespace = $tableField . '.' . $keyPublished;
			$publishedFieldAlias = static::tableFieldAlias($publishedNamespace);

			$this->select($publishedNamespace);


			$wherePublished = '(' . $publishedFieldAlias . ' = 1 OR ' . $publishedFieldAlias . ' IS NULL)'; //Published or undefined state

			// Allow some users to access (core.edit.state)
			if ($acl->get('core.edit.state'))
				$wherePublished = '1'; //Do not filter

			// FILTER - Published state
			$published = $this->model->getState('filter.' . $keyPublished);

			// Only apply filter on current table. And only if ACL permits.
			if (($tableField == 'a') && (is_numeric($published)) && $acl->get('core.edit.state'))
			{
				// Limit to publish state when filter is applied
				$wherePublished = $publishedFieldAlias . ' = ' . (int)$published;

				// Very important : Does not apply the author condition when filter is defined
				$allowAuthor = '0';
			}

			// Do not apply filter
			if ($wherePublished == '1')
				$wherePublished = null;
		}

		// Build the condition using a SQL composer
		$where = $this->sqlWhereConditions(array(

			// Restrictions
			$whereAccess,
			$wherePublished
		), array(

			// Permissions
			$allowAuthor
		));

		if ($where)
			$this->model->addWhere($where);
	}

	/**
	* Set the context on the model.
	*
	* @access	public
	* @param	string	$config	Context name.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function context($config)
	{
		$this->model->setState('context', (string)$config);
	}

	/**
	* Filter directive.
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filter($name, $config)
	{
		$type = 'string';
		if (isset($config['type']))
			$type = $config['type'];

		if (in_array($type, array('enum')))
			$type = 'string';

		// Not allowed
		if (!in_array($type, array('fk', 'multi', 'pivot', 'string', 'range', 'period')))
			return;

		$fct = 'filter' . ucfirst($type);
		$this->$fct($name, $config);
	}

	/**
	* Filter on a Foreign Key.
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Foreign Key Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filterFk($name, $config)
	{
		$stateName = 'filter.' . $name;

		// Force a value
		if (isset($config['value']))
			$this->model->setState($stateName, $config['value']);


		$value = $this->model->getState($stateName, null);
		if ($value === null)
			return;

		// Cast to int
		$value = (int)$value;

		if (isset($config['namespace']))
		{
			$namespace = $config['namespace'];
			// Join the requiremnts
			$this->select($namespace);

			$fieldAlias = static::tableFieldAlias($namespace);
		}
		else
			$fieldAlias = static::tableFieldAlias($name);

		$this->model->addWhere($fieldAlias . ' = ' . $value);
	}

	/**
	* Filter with multiple values.
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Multiple Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filterMulti($name, $config)
	{
		// Force a value
		if (isset($config['value']))
			$this->model->setState('filter.' . $name, $config['value']);

		$namespace = null;
		if (isset($config['namespace']))
			$namespace = $config['namespace'];

		$logic = null;
		if (isset($config['logic']))
			$logic = $config['logic'];


		$format = 'fk';
		if (isset($config['format']))
			$format = $config['format'];


		$values = array();
		if ($vals = $this->model->getState('filter.' . $name))
		{
			// Remove empty values
			if (is_array($vals))
				foreach($vals as $val)
					if (!empty($val))
						$values[] = $val;
		}

		if (empty($values))
			return;

		// JOIN the requirements
		if ($namespace)
			$this->join($namespace);

		if (isset($config['namespace']))
			$fieldAlias = static::tableFieldAlias($config['namespace']);
		else
			$fieldAlias = static::tableFieldAlias($name);

		$ids = array();
		switch($format)
		{
			case 'int':
			case 'fk':

				// Cast values
				foreach($values as $val)
					$ids[] = (int)$val;

				break;

			case 'cmd':
			case 'varchar':
			case 'enum':
				// Cast values
				foreach($values as $val)
					$ids[] = $this->_db->quote($val);

				break;
		}


		if (!count($ids))
			return;


		switch($logic)
		{
			// Exclude
			case 'NOT':
				$this->model->addWhere($fieldAlias . " NOT IN (" . implode(',', $ids) . ")");
				break;

			// Restrict
			default:
				$this->model->addWhere($fieldAlias . " IN (" . implode(',', $ids) . ")");
				break;
		}
	}

	/**
	* Filter over a period of time, using period strings.
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Period Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filterPeriod($name, $config)
	{
		if (array_key_exists('namespace', $config))
		{
			$namespace = $config['namespace'];

			// Join the requiremnts
			$this->select($namespace);

			$fieldAlias = static::tableFieldAlias($namespace);
		}
		else
			$fieldAlias = static::tableFieldAlias($name);

		// PERIOD
		$statePeriod = 'filter.' . $name;
		if (array_key_exists('value', $config))
			$this->model->setState($statePeriod, $config['value']);

		$value = $this->model->getState($statePeriod);

		// Search for null dates.
		if ($value == 'null')
		{
			$this->model->addWhere($fieldAlias . " IS NULL ");
			return;
		}

		// Search for defined dates.
		if ($value == 'defined')
		{
			$this->model->addWhere($fieldAlias . " <> NULL ");
			return;
		}


		// END
		$stateEnd = 'filter.' . $name . '.range';
		if (array_key_exists('range', $config))
			$this->model->setState($stateEnd, $config['range']);

		$valueRange = $this->model->getState($stateEnd);


		// Time cannot be null.
		$this->model->addWhere($fieldAlias . " IS NOT NULL ");


		// Use a shared function to transform period string to datetime bounds
		$range = $this->getPeriodRange($value, $valueRange);

		// Apply the STARTING time filter.
		if ($range['from'])
			$this->model->addWhere($fieldAlias . " >= " . $this->_db->quote($range['from']));

		// Apply the ENDING time filter.
		if ($range['to'])
			$this->model->addWhere($fieldAlias . " < " . $this->_db->quote($range['to']));
	}

	/**
	* Filter with a Xref value trough a pivot table (N:m).
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Pivot Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filterPivot($name, $config)
	{
		// Force a value
		if (isset($config['value']))
			$this->model->setState('filter.' . $name, $config['value']);

		$relationName = $name;
		if (isset($config['relation']))
			$relationName =  $config['relation'];

		$stateName = 'filter.' . $name;

		// Logic of the filter (AND|OR|NOT)
		if (isset($config['logic']))
		{
			$logic = $config['logic'];

			if (in_array($logic, array('AND', 'OR', 'NOT')))
				$this->model->setState($stateName . '.logic', $logic);
		}


		$stateName = 'filter.' . $relationName;

		if($values = $this->model->getState($stateName))
		{
			if (is_array($values))
			{
				$relation = $this->model->getRelation($relationName);

				// @logic Determines the behaviour of the filter
				$logic = strtoupper($this->model->getState($stateName . '.logic', 'AND'));
				switch ($logic)
				{
					case 'NOT':
					case 'OR':
						// Matches "at least one" value
						$conditions = array();
						foreach($values as $value)
						{
							if (empty($value))
								continue;

							$conditions[] = 'x.' . $relation->foreignKey . ' = ' . (int)$value;
						}

						if (count($conditions))
						{
							// Search for all related items matching the filter values
							$sql = $this->sqlBelongsOf($relation, $conditions);

							if ($logic == 'OR')
								// SQL Restriction list from the related items founds
								$this->model->addWhere("a.id IN (" . $sql . ")");
							else if ($logic == 'NOT')
								// SQL Exclusion of the related items founds.
								$this->model->addWhere("a.id NOT IN (" . $sql . ")");
						}

						break;

					case 'AND':
					default:

						// Match ALL values
						foreach($values as $value)
						{
							if (empty($value))
								continue;

							// Search for all related items matching the filter values
							$sql = $this->sqlBelongsOf($relation, array('x.' . $relation->foreignKey . ' = ' . (int)$value));

							// Restrict SQL list from the related items founds
							$this->model->addWhere("a.id IN (" . $sql . ")");
						}

						break;
				}
			}
		}
	}

	/**
	* Filter with a range of values.
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Pivot Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filterRange($name, $config)
	{
		// FROM
		$stateNameFrom = 'filter.' . $name . '_from';
		if (isset($config['from']))
			$this->model->setState($stateNameFrom, $config['from']);

		$valueFrom = $this->model->getState($stateNameFrom);


		// TO
		$stateNameTo = 'filter.' . $name . '_to';
		if (isset($config['to']))
			$this->model->setState($stateNameTo, $config['to']);

		$valueTo = $this->model->getState($stateNameTo);


		// Not allowed
		if (is_array($valueFrom) || is_array($valueTo))
			return;

		if (empty($valueFrom) && empty($valueTo))
			return;

		if (isset($config['namespace']))
		{
			$namespace = $config['namespace'];

			// Join the requiremnts
			$this->select($namespace);

			$fieldAlias = static::tableFieldAlias($namespace);
		}
		else
			$fieldAlias = static::tableFieldAlias($name);


		if (!empty($valueFrom))
		{
			$valueFrom = $this->_db->quote($valueFrom);
			$this->model->addWhere($fieldAlias . ' >= ' . $valueFrom);
		}


		if (!empty($valueTo))
		{
			$valueTo = $this->_db->quote($valueTo);
			$this->model->addWhere($fieldAlias . ' <= ' . $valueTo);
		}
	}

	/**
	* Filter with a string value.
	*
	* @access	public
	* @param	string	$name	Unique filter name.
	* @param	array	$config	Filter configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function filterString($name, $config)
	{
		$stateName = 'filter.' . $name;

		// Force a value
		if (isset($config['value']))
			$this->model->setState($stateName, $config['value']);

		$default = null;
		if (isset($config['default']))
			$default = $config['default'];

		$value = $this->model->getState($stateName, $default);

		// Not allowed
		if (is_array($value))
			return;

		if (empty($value))
			return;

		if (isset($config['namespace']))
		{
			$namespace = $config['namespace'];

			// Join the requiremnts
			$this->select($namespace);

			$fieldAlias = static::tableFieldAlias($namespace);
		}
		else
			$fieldAlias = static::tableFieldAlias($name);

		$value = $this->_db->quote($value);

		$this->model->addWhere($fieldAlias . ' = ' . $value);
	}

	/**
	* Get an ORM object.
	*
	* @access	public static
	* @param	JModel	$model	Model where ORM applies.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public static function getInstance($model)
	{
		return new ContactpushClassModelOrm($model);
	}

	/**
	* Get a model from a namespaced model name.
	*
	* @access	public static
	* @param	string	$modelName	Namespaced model. First part is the component name.
	*
	*
	* @since	Cook 3.1
	*
	* @return	JModel	Model.
	*/
	public static function getModel($modelName)
	{
		// Per default
		$extension = 'Contactpush';

		$parts = explode('.', $modelName);
		if (count($parts) > 1)
		{
			$extension = $parts[0];
			$modelName = $parts[1];
		}

		$model = CkJModel::getInstance($modelName, ucfirst($extension) . 'Model');

		return $model;
	}

	/**
	* Transform period string to SQL datetime bounds.
	*
	* @access	protected
	* @param	string	$period	Period string. Can be : today|now|null|defined or period string ex: +1day
	* @param	string	$range	Range string. Can be : period string ex: +1day
	*
	*
	* @since	Cook 3.1
	*
	* @return	array	Containing FROM and TO is a SQL format.
	*/
	protected function getPeriodRange($period, $range = null)
	{
		// Get UTC for now.
		$dNow = new JDate;
		$dFrom = clone $dNow;

		// Define the starting time.
		switch($period)
		{

			case 'now':
				// 1 hour back per default.
				$dFrom->modify('-1 hour');
				$dTo = clone $dNow;
				break;

			case 'today':
				//Align on the days bounds

				// Ranges that need to align with local 'days' need special treatment.
				$app	= JFactory::getApplication();
				$offset	= $app->getCfg('offset');

				// Reset the start time to be the beginning of today, local time.
				$dFrom	= new JDate('now', $offset);
				$dFrom->setTime(0, 0, 0);

				// Now change the timezone back to UTC.
				$tz = new DateTimeZone('GMT');
				$dFrom->setTimezone($tz);

				// End of the day
				$dTo = clone $dFrom;
				$dTo->modify('+1day');
				break;

			default:
				$dFrom->modify($period);
				$dTo = clone $dFrom;
			break;
		}


		//Define the ending time.
		switch($range)
		{
			case null: break;

			default:

				$dTo = clone $dFrom;
				$dTo->modify($range);
			break;
		}


		return array(
			'from' => ($dFrom?$dFrom->toSql():null),
			'to' => ($dTo?$dTo->toSql():null)
		);
	}

	/**
	* Group directive.
	*
	* @access	public
	* @param	array	$config	Groups configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function groupOrder($config)
	{
		foreach($config as $namespace => $dir)
		{
			if (!in_array($dir, array('ASC', 'DESC'), true))
				$dir = 'ASC';

			$fieldAlias = static::tableFieldAlias($namespace);

			// Requirements
			$this->select($namespace);

			$this->model->addQuery('groupOrder', $fieldAlias . ' ' . $dir);
		}
	}

	/**
	* Rule to filter the unique item.
	*
	* @access	public
	* @param	mixed	$config	array|string. Configuration of the filter.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function id($config)
	{
		$id = (int)$this->model->getState($this->model->getName() . '.id');

		// Over the primary key
		if (is_string($config) || is_integer($config))
		{
			$value = $config;

			// Get the primary key field name
			$field = $this->model->getNamePk();

			// Automatic value from the id state var
			$value = ($value == 'id'?$id:$value);

			// Pk used for cache store ID
			$storeId = $value;

			// Filter on the Id key
			$this->model->addWhere('a.' . $field . ' = ' . (int)$value);
		}

		// Custom filter
		else if (is_array($config) && count($config))
		{
			$storeId = array();
			foreach($config as $namespace => $value)
			{
				// Automatic values
				switch($value)
				{
					// Pick the ID from the state vars
					case 'id':
						$value = $id;
						break;

					// Pick the User ID from the application
					case 'user':
						$value = JFactory::getUser()->get('id');
						break;
				}

				// Joining requirements
				$this->join($namespace);

				// Can base the item selection on any namespaced field
				$fieldAlias = static::tableFieldAlias($namespace);

				// Create the cache store ID
				$storeId[] = $fieldAlias . ':' . $value;

				$value = $this->_db->quote($value);
				$this->model->addWhere($fieldAlias . ' = ' . $value);
			}

			$storeId = implode(',', $storeId);

		}

		$this->model->setState('id', $storeId);
	}

	/**
	* Join a required namespace.
	*
	* @access	public
	* @param	string	$namespace	Namespaced field.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function join($namespace)
	{
		$parts = explode('.', $namespace);
		$model = $this->model;

		// Optimization : Do not join anything on a root field
		if ($parts[0] == 'a')
			return;

		$currentNamespace = $parts[0];

		for ($depth = 0 ; $depth < count($parts) - 1 ; $depth++)
		{
			$field = $parts[$depth];
			$relation = $model->getRelation($field);

			// Not allowed
			if (!$relation || $relation->type != "hasOne")
				return;

			$localKey = $relation->localKey;
			if ($depth > 0)
			{
				$localKey = $currentNamespace . '.' . $localKey;
				$currentNamespace .= '.' . $field;

				// Select all nodes
				$this->select($localKey);
			}

			$localKey = static::tableFieldAlias($localKey);
			$fkTableAlias = '_' . str_replace('.', '_', $currentNamespace) . '_';


			$this->model->addJoin('`' . $relation->foreignTable . '` AS ' . $fkTableAlias
				. ' ON ' . $fkTableAlias . '.' . $relation->foreignKey . ' = ' . $localKey, 'LEFT');

			$partsModel = explode('.', $relation->foreignModelClass);
			$modelName = $partsModel[1];
			$extension = $partsModel[0];

			if (!empty($extension))
				$model = CkJModel::getInstance($modelName, ucfirst($extension) . 'Model');
		}
	}

	/**
	* Ordering directive.
	*
	* @access	public
	* @param	array	$config	Ordering configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function order($config)
	{
		foreach($config as $namespace => $dir)
		{
			$dir = strtoupper($dir);

			if (!in_array($dir, array('ASC', 'DESC'), true))
				$dir = 'ASC';

			if (substr($namespace, 0, 1) == '_')
				$fieldAlias = $namespace; // Supports legacy ordering
			else
			{
				$fieldAlias = static::tableFieldAlias($namespace);

				// Requirements
				$this->join($namespace);
			}

			$this->model->addQuery('order', $fieldAlias . ' ' . $dir);
		}
	}

	/**
	* Pagination directive.
	*
	* @access	public
	* @param	array	$config	Pagination configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function pagination($config)
	{
		if (array_key_exists('limit', $config))
			$this->model->setState('list.limit', $config['limit']);

		if (array_key_exists('start', $config))
			$this->model->setState('list.start', $config['start']);
	}

	/**
	* Developper function. Dump the query to the screen.
	*
	* @access	public static
	* @param	JDatabaseQuery	$query	Query to dump.
	* @param	boolean	$output	Print the query description to the standard output.
	*
	*
	* @since	Cook 3.1
	*
	* @return	array	Query description.
	*/
	public static function queryDump($query, $output = true)
	{
		$obj = new stdClass();

		// FROM
		if ($query->from && ($from = $query->from->getElements()))
			if (count($from))
				$obj->FROM = $from[0];



		// SELECT
		if (count($query->select))
		{
			$obj->SELECT = $query->select->getElements();
		}

		// JOIN
		$joins = array();
		if (count($query->join))
		{
			foreach($query->join as $join)
			{
				foreach($join->getElements() as $joinElement)
				{
					$joins[] = $joinElement;
				}
			}
			$obj->JOIN = $joins;
		}

		// WHERE
		$where = array();
		if ($query->where)
		{
			foreach($query->where->getElements() as $whereElement)
			{
				$where[] = $whereElement;
			}

			$obj->WHERE = $where;
		}


		// ORDER BY
		if (isset($query->order))
			$obj->ORDER_BY = $query->order->getElements();



		if ($output)
		{
			echo("<pre>"); print_r($obj); echo("</pre>");
			echo("<pre>"); print_r((string)$query); echo("</pre>");
		}

		return $obj;
	}

	/**
	* Prepare a relation.
	* Stores the ORM description into a state var (relation.xxxx).
	* populateObjects() will then catch it and load the related items.
	*
	* @access	public
	* @param	string	$name	Relation name.
	* @param	array	$config	Relation sub-query configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function relation($name, $config)
	{
		// Store the relation ORM configuration into states for further use (AFTER getting items)
		$this->model->setState('relation.' . $name, $config);
	}

	/**
	* Search directive.
	*
	* @access	public
	* @param	string	$name	Unique search name.
	* @param	array	$config	Search configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function search($name, $config)
	{
		// Required param
		if (!isset($config['on']))
			return;

		$stateName = 'search.' . $name;
		// Force a value
		if (isset($config['value']))
			$this->model->setState($stateName, $config['value']);


		$value = $this->model->getState($stateName);

		// Empty value
		if ($value == '')
			return;

		//SPLIT SEARCHED TEXT
		$searchesParts = array();
		foreach(explode(" ", $value) as $searchStr)
		{
			$searchStr = trim($searchStr);
			if ($searchStr == '')
				continue;

			if ((isset($config['ignoredLength'])) && (strlen($searchStr) <= $config['ignoredLength']))
				continue;


			$tests = array();
			foreach($config['on'] as $namespace => $method)
			{
				$fieldAlias = static::tableFieldAlias($namespace);

				// Join requirements
				$this->join($namespace);

				switch($method)
				{
					case 'like':

						$searchStr = $this->_db->escape($searchStr);
						$test = $fieldAlias . " LIKE " . $this->_db->quote("%" . $searchStr . "%");
						break;

					case 'exact':
						$test = $fieldAlias . " = " . $this->_db->quote($searchStr);
						break;

					default:
						continue;
						break;
				}

				$tests[] = $test;
			}

			$searchesParts[] = "(" . implode(" OR ", $tests) . ")";
		}


		if (!count($searchesParts))
			return;


		$logic = 'AND';
		if (isset($config['logic']))
		{
			$log = strtoupper($config['logic']);
			if (in_array($log, array('AND', 'OR')))
				$logic = $log;
		}


		$where = implode(" " . $logic . " ", $searchesParts);

		$this->model->addWhere($where);
	}

	/**
	* Select directive.
	*
	* @access	public
	* @param	array|string	$config	List of desired fields and namespaces or field alone.
	* @param	string	$alias	Defines an alias for the requested field (when @config is a string).
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function select($config, $alias = null)
	{
		// config is an array
		if (is_array($config))
		{
			foreach($config as $index => $value)
			{
				// Simple SELECT
				if (is_numeric($index))
					$this->select($value);

				// SELECT with alias
				else
					$this->select($index, $value);
			}

			return;
		}

		// config is a coma separated string
		if (strpos($config, ','))
		{
			foreach(explode(',', $config) as $namespace)
				$this->select($namespace);
			return;
		}

		$namespace = $config;

		if (empty($namespace))
			return;

		$parts = explode('.' ,$namespace);

		$isFk = (($parts[0] != 'a') && (count($parts) > 1));

		// Root field
		if (!$isFk)
		{
			// Instance the field in query
			$this->model->addSelect(static::tableFieldAlias($namespace) . ($alias?' AS ' . $alias:''));
		}

		// Foreign Key
		else
		{
			// Physical field name is always the last part
			$fieldname = $parts[count($parts)-1];
			$current = $parts[0];

			$parentTable = 'a';

			for($depth = 0 ; $depth < (count($parts)) ; $depth++)
			{
				$current = $parts[$depth];

				// Last
				if ($depth == (count($parts) - 1))
					break;

				$tableAlias = '_' . $current . '_';

				// Concat the table alias
				if ($parentTable == 'a')
					$parentTable = $tableAlias;
				else
					$parentTable .= $current . '_';
			}

			// Create the field var name for the model
			$fieldVar = '_' . str_replace('.', '_', $namespace);

			if (empty($alias))
				$alias = $this->_db->quoteName($fieldVar);

			// Instance the field in query with alias
			$this->model->addSelect($parentTable .'.'. $current . ' AS ' . $alias);

			// JOIN the requirements
			$this->join($namespace);
		}
	}

	/**
	* Add an ORM request.
	*
	* @access	public
	* @param	array	$description	ORM description.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function set($description)
	{
		if (empty($description))
			return;

		foreach($description as $directive => $config)
		{
			switch($directive)
			{
				case 'id':
				case 'context':
				case 'select':
				case 'groupOrder':
				case 'order':
				case 'pagination':
					$this->$directive($config);
					break;


				case 'access':
				case 'filter':
				case 'search':
				case 'relation':
				case 'version':
					foreach($config as $name => $options)
						$this->$directive($name, $options);
					break;
			}
		}
	}

	/**
	* Construct a SQL query filter, containings IDs of local table, belonging to
	* a cross-reference table (N:m).
	*
	* @access	protected
	* @param	string	$relation	Relation name.
	* @param	array	$conditions	Conditions to match on the cross-reference foreign table (N:m).
	*
	*
	* @since	Cook 3.1
	*
	* @return	string	SQL query returning local Id's.
	*/
	protected function sqlBelongsOf($relation, $conditions)
	{
		if ($relation->type != 'belongsToMany')
			return null;

		$query = $this->_db->getQuery(true);

		// Only works from the pivot table (alias: `p`)
		$query->select('p.' . $relation->pivotLocalKey);
		$query->from($relation->pivotTable . ' AS p');

		// Link the Foreign Table
		$query->join('LEFT', $this->_db->quoteName($relation->foreignTable) . ' AS x '
			. ' ON x.' . $relation->foreignKey . ' = p.' . $relation->pivotForeignKey
		);

		// Concat all conditions with a 'OR' statement
		if (!empty($conditions))
		{
			$condition = '(' . implode(' OR ', $conditions) . ')';
			$query->where($condition);
		}

		return (string)$query;
	}

	/**
	*  Build the SQL Condition string. Optimize and clean the useless logic.
	* Structure : (RESTRICT && RESTRICT && RESTRICT) || ALLOW || ALLOW || ALLOW
	*
	* @access	protected
	* @param	array	$restricts	Restrictions conditions (AND).
	* @param	array	$allows	Permissions conditions (OR).
	*
	*
	* @since	Cook 3.1
	*
	* @return	string	SQL condition.
	*/
	protected function sqlWhereConditions($restricts, $allows)
	{
		$where = null;


		// RESTRICTIONS
		$restrictions = array();


		$isRestricted = false;
		foreach ($restricts as $restrict)
		{
			// No condition > Skip
			if (empty($restrict))
				continue;

			// (... AND 1) > Nop
			if ($restrict == '1')
				continue;


			// (... AND 0) > Always 0
			if ($restrict == '0')
				$isRestricted = true;


			$restrictions[] = $restrict;
		}


		if ($isRestricted)
			$where = '0';
		else
		{
			// Concat the restrictions conditions with AND
			$where = implode(' AND ', $restrictions);

			// Make sure all restrictions are grouped into one required condition
			if (count($restrictions))
				$where = '(' . $where . ')';

		}


		// No restrictions. No need to invoke the ALLOW statement.
		if (!$where)
			return;


		// ( ... OR 1) > Always true
		// To that point there is no restriction
		if (!$where || ($where == '1'))
			return;



		// ALLOW

		$allowing = array();
		foreach ($allows as $allow)
		{
			if (empty($allow))
				continue;

			// (... OR 0) > Ignore statement
			if ($allow != '0')
				$allowing[] = $allow;
		}


		if (count($allowing))
		{
			// Concat the restrictions conditions with OR
			$where = $where . ' OR ' . implode(' OR ', $allowing);

			// Make sure all statemeents are grouped into one condition
			$where = '(' . $where . ')';
		}


		return $where;
	}

	/**
	* Get the alias of a namespaced field.
	*
	* @access	public static
	* @param	string	$namespace	Namespaced name.
	* @param	string	$sqlPath	Return SQL table base per default. Set to false to return the field alias name.
	*
	*
	* @since	Cook 3.1
	*
	* @return	string	Aliased field.
	*/
	public static function tableFieldAlias($namespace, $sqlPath = true)
	{
		$parts = explode('.', $namespace);

		$table = 'a';
		$alias = '';

		foreach($parts as $part)
		{
			$alias = $table . ($sqlPath?'.':'') . $part;

			if ($part != 'a')
			{
				if ($table == 'a')
					$table = '_';

				$table .= $part . '_';
			}
		}

		return $alias;
	}

	/**
	* Get the table name of a namespaced foreign key.
	*
	* @access	protected
	* @param	string	$namespace	Namespaced foreign key.
	*
	*
	* @since	Cook 3.1
	*
	* @return	string	Table name of the last field FK.
	*/
	protected function tableName($namespace)
	{
		$parts = explode('.', $namespace);
		$model = $this->model;

		$extension = 'contactpush';
		$table = $model->getName();

		if ($parts[0] == 'a')
			array_shift($parts);

		$currentNamespace = $parts[0];

		for ($depth = 0 ; $depth < count($parts) ; $depth++)
		{
			if ($depth > 0)
				$model = CkJModel::getInstance($table, ucfirst($extension) . 'Model');


			$field = $parts[$depth];
			$relation = $model->getRelation($field);

			// Not a relation
			if (!$relation)
				break;

			// Not a Foreign Key
			if ($relation->type != "hasOne")
				break;

			$partsModel = explode('.', $relation->foreignModelClass);
			$extension = $partsModel[0];
			$table = $partsModel[1];
		}

		return '#__' . ($extension?$extension.'_':'') . $table;
	}

	/**
	* Content Versioning directive.
	*
	* @access	public
	* @param	string	$name	Unique search name.
	* @param	array	$config	Translation configuration.
	*
	*
	* @since	Cook 3.1
	*
	* @return	void
	*/
	public function version($name, $config)
	{

	}


}

// Load the fork
ContactpushHelper::loadFork(__FILE__);

// Fallback if no fork has been found
if (!class_exists('ContactpushClassModelOrm')){ class ContactpushClassModelOrm extends ContactpushCkClassModelOrm{} }