How can you get a list of the executed queries when debug is set to 0 ?
I have the following functions in AppController:
// log INSERT, UPDATE, DELETE queries
private function __logQueries(){
$db = &ConnectionManager::getDataSource('default');
$query_logs = $db->getLog();
if( isset($query_logs['log']) && !empty($query_logs['log']) ){
$this->loadModel('SqlLog');
foreach($query_logs['log'] as $log_q){
$query = $log_q['query'];
if( stristr($query, 'INSERT ') || stristr($query, 'UPDATE ') || stristr($query, 'DELETE ') ){
$q_data = array(
'query' => $query,
'page' => $this->Misc->getCurrentPageURL(), // get the current page
'referrer' => trim(env('HTTP_REFERER')) == '' ? '' : env('HTTP_REFERER'),
'ip' => env('REMOTE_ADDR'),
'browser' => env('HTTP_USER_AGENT'),
'user_id' => SessionComponent::check('Auth.User') ? SessionComponent::read('Auth.User.id') : 0,
'username' => SessionComponent::check('Auth.User') ? addslashes(SessionComponent::read('Auth.User.username')) : '',
);
$this->SqlLog->create();
$this->SqlLog->save($q_data);
}
}
} // end if query occured
}
public function beforeRedirect(){
$this->__logQueries();
}
public function afterFilter(){
$this->__logQueries();
}
The insert, update and delete queries get logged when debug is set to 2, but how can I log those queries when debug is set to 0?
Whether queries are being logged depends on the DboSource::$fullDebug property, it's being set in the DboSource constructur, and by default it's true in case debug is > 1.
So all you have to do is overwrite the value of this property with true, this will ensure that as of this point the queries are being logged regardless of the debug setting.
App::uses('ConnectionManager', 'Model');
ConnectionManager::getDataSource('default')->fullDebug = true;
Create your own dbo file in the specified path:
\app\models\datasources\dbo\dbo_mysql_with_log.php
and the content of this file will be
<?php
class DboMysqlBase extends DboSource {
/**
* Description property.
*
* #var string
*/
var $description = "MySQL DBO Base Driver";
/**
* Start quote
*
* #var string
*/
var $startQuote = "`";
/**
* End quote
*
* #var string
*/
var $endQuote = "`";
/**
* use alias for update and delete. Set to true if version >= 4.1
*
* #var boolean
* #access protected
*/
var $_useAlias = true;
/**
* Index of basic SQL commands
*
* #var array
* #access protected
*/
var $_commands = array(
'begin' => 'START TRANSACTION',
'commit' => 'COMMIT',
'rollback' => 'ROLLBACK'
);
/**
* MySQL column definition
*
* #var array
*/
var $columns = array(
'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'),
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
'binary' => array('name' => 'blob'),
'boolean' => array('name' => 'tinyint', 'limit' => '1')
);
/**
* Generates and executes an SQL UPDATE statement for given model, fields, and values.
*
* #param Model $model
* #param array $fields
* #param array $values
* #param mixed $conditions
* #return array
*/
function update(&$model, $fields = array(), $values = null, $conditions = null) {
if (!$this->_useAlias) {
return parent::update($model, $fields, $values, $conditions);
}
if ($values == null) {
$combined = $fields;
} else {
$combined = array_combine($fields, $values);
}
$alias = $joins = false;
$fields = $this->_prepareUpdateFields($model, $combined, empty($conditions), !empty($conditions));
$fields = join(', ', $fields);
$table = $this->fullTableName($model);
if (!empty($conditions)) {
$alias = $this->name($model->alias);
if ($model->name == $model->alias) {
$joins = implode(' ', $this->_getJoins($model));
}
}
$conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
if ($conditions === false) {
return false;
}
if (!$this->execute($this->renderStatement('update', compact('table', 'alias', 'joins', 'fields', 'conditions')))) {
$model->onError();
return false;
}
return true;
}
/**
* Generates and executes an SQL DELETE statement for given id/conditions on given model.
*
* #param Model $model
* #param mixed $conditions
* #return boolean Success
*/
function delete(&$model, $conditions = null) {
if (!$this->_useAlias) {
return parent::delete($model, $conditions);
}
$alias = $this->name($model->alias);
$table = $this->fullTableName($model);
$joins = implode(' ', $this->_getJoins($model));
if (empty($conditions)) {
$alias = $joins = false;
}
$conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
if ($conditions === false) {
return false;
}
if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
$model->onError();
return false;
}
return true;
}
/**
* Sets the database encoding
*
* #param string $enc Database encoding
*/
function setEncoding($enc) {
return $this->_execute('SET NAMES ' . $enc) != false;
}
/**
* Returns an array of the indexes in given datasource name.
*
* #param string $model Name of model to inspect
* #return array Fields in table. Keys are column and unique
*/
function index($model) {
$index = array();
$table = $this->fullTableName($model);
if ($table) {
$indexes = $this->query('SHOW INDEX FROM ' . $table);
if (isset($indexes[0]['STATISTICS'])) {
$keys = Set::extract($indexes, '{n}.STATISTICS');
} else {
$keys = Set::extract($indexes, '{n}.0');
}
foreach ($keys as $i => $key) {
if (!isset($index[$key['Key_name']])) {
$col = array();
$index[$key['Key_name']]['column'] = $key['Column_name'];
$index[$key['Key_name']]['unique'] = intval($key['Non_unique'] == 0);
} else {
if (!is_array($index[$key['Key_name']]['column'])) {
$col[] = $index[$key['Key_name']]['column'];
}
$col[] = $key['Column_name'];
$index[$key['Key_name']]['column'] = $col;
}
}
}
return $index;
}
/**
* Generate a MySQL Alter Table syntax for the given Schema comparison
*
* #param array $compare Result of a CakeSchema::compare()
* #return array Array of alter statements to make.
*/
function alterSchema($compare, $table = null) {
if (!is_array($compare)) {
return false;
}
$out = '';
$colList = array();
foreach ($compare as $curTable => $types) {
$indexes = array();
if (!$table || $table == $curTable) {
$out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
foreach ($types as $type => $column) {
if (isset($column['indexes'])) {
$indexes[$type] = $column['indexes'];
unset($column['indexes']);
}
switch ($type) {
case 'add':
foreach ($column as $field => $col) {
$col['name'] = $field;
$alter = 'ADD '.$this->buildColumn($col);
if (isset($col['after'])) {
$alter .= ' AFTER '. $this->name($col['after']);
}
$colList[] = $alter;
}
break;
case 'drop':
foreach ($column as $field => $col) {
$col['name'] = $field;
$colList[] = 'DROP '.$this->name($field);
}
break;
case 'change':
foreach ($column as $field => $col) {
if (!isset($col['name'])) {
$col['name'] = $field;
}
$colList[] = 'CHANGE '. $this->name($field).' '.$this->buildColumn($col);
}
break;
}
}
$colList = array_merge($colList, $this->_alterIndexes($curTable, $indexes));
$out .= "\t" . join(",\n\t", $colList) . ";\n\n";
}
}
return $out;
}
/**
* Generate a MySQL "drop table" statement for the given Schema object
*
* #param object $schema An instance of a subclass of CakeSchema
* #param string $table Optional. If specified only the table name given will be generated.
* Otherwise, all tables defined in the schema are generated.
* #return string
*/
function dropSchema($schema, $table = null) {
if (!is_a($schema, 'CakeSchema')) {
trigger_error(__('Invalid schema object', true), E_USER_WARNING);
return null;
}
$out = '';
foreach ($schema->tables as $curTable => $columns) {
if (!$table || $table == $curTable) {
$out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n";
}
}
return $out;
}
/**
* Generate MySQL index alteration statements for a table.
*
* #param string $table Table to alter indexes for
* #param array $new Indexes to add and drop
* #return array Index alteration statements
*/
function _alterIndexes($table, $indexes) {
$alter = array();
if (isset($indexes['drop'])) {
foreach($indexes['drop'] as $name => $value) {
$out = 'DROP ';
if ($name == 'PRIMARY') {
$out .= 'PRIMARY KEY';
} else {
$out .= 'KEY ' . $name;
}
$alter[] = $out;
}
}
if (isset($indexes['add'])) {
foreach ($indexes['add'] as $name => $value) {
$out = 'ADD ';
if ($name == 'PRIMARY') {
$out .= 'PRIMARY ';
$name = null;
} else {
if (!empty($value['unique'])) {
$out .= 'UNIQUE ';
}
}
if (is_array($value['column'])) {
$out .= 'KEY '. $name .' (' . join(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
} else {
$out .= 'KEY '. $name .' (' . $this->name($value['column']) . ')';
}
$alter[] = $out;
}
}
return $alter;
}
/**
* Inserts multiple values into a table
*
* #param string $table
* #param string $fields
* #param array $values
*/
function insertMulti($table, $fields, $values) {
$table = $this->fullTableName($table);
if (is_array($fields)) {
$fields = join(', ', array_map(array(&$this, 'name'), $fields));
}
$values = implode(', ', $values);
$this->query("INSERT INTO {$table} ({$fields}) VALUES {$values}");
}
}
class DboMysql extends DboMysqlBase {
/**
* Enter description here...
*
* #var unknown_type
*/
var $description = "MySQL DBO Driver";
/**
* Base configuration settings for MySQL driver
*
* #var array
*/
var $_baseConfig = array(
'persistent' => true,
'host' => 'localhost',
'login' => 'root',
'password' => '',
'database' => 'cake',
'port' => '3306',
'connect' => 'mysql_pconnect'
);
/**
* Connects to the database using options in the given configuration array.
*
* #return boolean True if the database could be connected, else false
*/
function connect() {
$config = $this->config;
$connect = $config['connect'];
$this->connected = false;
if (!$config['persistent']) {
$this->connection = mysql_connect($config['host'] . ':' . $config['port'], $config['login'], $config['password'], true);
} else {
$this->connection = $connect($config['host'] . ':' . $config['port'], $config['login'], $config['password']);
}
if (mysql_select_db($config['database'], $this->connection)) {
$this->connected = true;
}
if (isset($config['encoding']) && !empty($config['encoding'])) {
$this->setEncoding($config['encoding']);
}
$this->_useAlias = (bool)version_compare(mysql_get_server_info($this->connection), "4.1", ">=");
return $this->connected;
}
/**
* Disconnects from database.
*
* #return boolean True if the database could be disconnected, else false
*/
function disconnect() {
if (isset($this->results) && is_resource($this->results)) {
mysql_free_result($this->results);
}
$this->connected = !#mysql_close($this->connection);
return !$this->connected;
}
/**
* Executes given SQL statement.
*
* #param string $sql SQL statement
* #return resource Result resource identifier
* #access protected
*/
function _execute($sql) {
return mysql_query($sql, $this->connection);
}
/**
* Returns an array of sources (tables) in the database.
*
* #return array Array of tablenames in the database
*/
function listSources() {
$cache = parent::listSources();
if ($cache != null) {
return $cache;
}
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');
if (!$result) {
return array();
} else {
$tables = array();
while ($line = mysql_fetch_array($result)) {
$tables[] = $line[0];
}
parent::listSources($tables);
return $tables;
}
}
/**
* Returns an array of the fields in given table name.
*
* #param string $tableName Name of database table to inspect
* #return array Fields in table. Keys are name and type
*/
function describe(&$model) {
$cache = parent::describe($model);
if ($cache != null) {
return $cache;
}
$fields = false;
$cols = $this->query('DESCRIBE ' . $this->fullTableName($model));
foreach ($cols as $column) {
$colKey = array_keys($column);
if (isset($column[$colKey[0]]) && !isset($column[0])) {
$column[0] = $column[$colKey[0]];
}
if (isset($column[0])) {
$fields[$column[0]['Field']] = array(
'type' => $this->column($column[0]['Type']),
'null' => ($column[0]['Null'] == 'YES' ? true : false),
'default' => $column[0]['Default'],
'length' => $this->length($column[0]['Type']),
);
if (!empty($column[0]['Key']) && isset($this->index[$column[0]['Key']])) {
$fields[$column[0]['Field']]['key'] = $this->index[$column[0]['Key']];
}
}
}
$this->__cacheDescription($this->fullTableName($model, false), $fields);
return $fields;
}
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* #param string $data String to be prepared for use in an SQL statement
* #param string $column The column into which this data will be inserted
* #param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
* #return string Quoted and escaped data
*/
function value($data, $column = null, $safe = false) {
$parent = parent::value($data, $column, $safe);
if ($parent != null) {
return $parent;
}
if ($data === null || (is_array($data) && empty($data))) {
return 'NULL';
}
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
return "''";
}
if (empty($column)) {
$column = $this->introspectType($data);
}
switch ($column) {
case 'boolean':
return $this->boolean((bool)$data);
break;
case 'integer':
case 'float':
if ($data === '') {
return 'NULL';
}
if ((is_int($data) || is_float($data) || $data === '0') || (
is_numeric($data) && strpos($data, ',') === false &&
$data[0] != '0' && strpos($data, 'e') === false)) {
return $data;
}
default:
$data = "'" . mysql_real_escape_string($data, $this->connection) . "'";
break;
}
return $data;
}
/**
* Returns a formatted error message from previous database operation.
*
* #return string Error message with error number
*/
function lastError() {
if (mysql_errno($this->connection)) {
return mysql_errno($this->connection).': '.mysql_error($this->connection);
}
return null;
}
/**
* Returns number of affected rows in previous database operation. If no previous operation exists,
* this returns false.
*
* #return integer Number of affected rows
*/
function lastAffected() {
if ($this->_result) {
return mysql_affected_rows($this->connection);
}
return null;
}
/**
* Returns number of rows in previous resultset. If no previous resultset exists,
* this returns false.
*
* #return integer Number of rows in resultset
*/
function lastNumRows() {
if ($this->hasResult()) {
return mysql_num_rows($this->_result);
}
return null;
}
/**
* Returns the ID generated from the previous INSERT operation.
*
* #param unknown_type $source
* #return in
*/
function lastInsertId($source = null) {
$id = $this->fetchRow('SELECT LAST_INSERT_ID() AS insertID', false);
if ($id !== false && !empty($id) && !empty($id[0]) && isset($id[0]['insertID'])) {
return $id[0]['insertID'];
}
return null;
}
/**
* Converts database-layer column types to basic types
*
* #param string $real Real database-layer column type (i.e. "varchar(255)")
* #return string Abstract column type (i.e. "string")
*/
function column($real) {
if (is_array($real)) {
$col = $real['name'];
if (isset($real['limit'])) {
$col .= '('.$real['limit'].')';
}
return $col;
}
$col = str_replace(')', '', $real);
$limit = $this->length($real);
if (strpos($col, '(') !== false) {
list($col, $vals) = explode('(', $col);
}
if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
return $col;
}
if (($col == 'tinyint' && $limit == 1) || $col == 'boolean') {
return 'boolean';
}
if (strpos($col, 'int') !== false) {
return 'integer';
}
if (strpos($col, 'char') !== false || $col == 'tinytext') {
return 'string';
}
if (strpos($col, 'text') !== false) {
return 'text';
}
if (strpos($col, 'blob') !== false || $col == 'binary') {
return 'binary';
}
if (strpos($col, 'float') !== false || strpos($col, 'double') !== false || strpos($col, 'decimal') !== false) {
return 'float';
}
if (strpos($col, 'enum') !== false) {
return "enum($vals)";
}
return 'text';
}
/**
* Enter description here...
*
* #param unknown_type $results
*/
function resultSet(&$results) {
if (isset($this->results) && is_resource($this->results) && $this->results != $results) {
mysql_free_result($this->results);
}
$this->results =& $results;
$this->map = array();
$numFields = mysql_num_fields($results);
$index = 0;
$j = 0;
while ($j < $numFields) {
$column = mysql_fetch_field($results,$j);
if (!empty($column->table)) {
$this->map[$index++] = array($column->table, $column->name);
} else {
$this->map[$index++] = array(0, $column->name);
}
$j++;
}
}
/**
* Fetches the next row from the current result set
*
* #return unknown
*/
function fetchResult() {
if ($row = mysql_fetch_row($this->results)) {
$resultRow = array();
$i = 0;
foreach ($row as $index => $field) {
list($table, $column) = $this->map[$index];
$resultRow[$table][$column] = $row[$index];
$i++;
}
return $resultRow;
} else {
return false;
}
}
/**
* Gets the database encoding
*
* #return string The database encoding
*/
function getEncoding() {
return mysql_client_encoding($this->connection);
}
}
class DboMysqlWithLog extends DboMysql {
function _execute($sql) {
//exclude these types of queries from being logged, change if required
if(!preg_match('/^SHOW|SELECT|DESCRIBE|cake_sessions.*/',$sql) && !preg_match('/^SET.*/',$sql)){
//HH_DOCUMENT_ROOT should be defined in one of the core files pointing to the project root directory, if its not there define it
//do not commit changes, if its specific to local machine
//$filename = HH_DOCUMENT_ROOT.DS.'sql.txt';
$filename = 'C:\xampp\htdocs\your_project_dir\app\sql.txt';
$patfile = fopen($filename, 'a+');
$textdata = "$sql\n";
fwrite($patfile, $textdata);
fclose($patfile);
}
return parent::_execute($sql);
}
}
?>
change sql log file path $filename = 'C:\xampp\htdocs\your_project_dir\app\sql.txt';
Step 2: Open /app/config/database.php
and change 'driver' => 'dbo_mysql_with_log',
This will record all your sql scripts in the below path
C:\xampp\htdocs\your_project_dir\app\sql.txt
Related
there is a page which is updated every 5-7 seconds, and on it records from the base are updated, but moments these records are duplicated, Do not tell me why this bug can be?
is a ActiveCaller model
namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class ActiveCaller extends Model
{
protected $fillable = ['queue', 'employee_id', 'station', 'state', 'duration',
'client_id', 'last_call'];
public function Employee()
{
return $this->belongsTo(Employee::class);
}
/**
* Convert duration attribute to acceptable format
*
* #param $value
* #return string
*/
public function getDurationAttribute($value)
{
if (empty($value))
return $value;
return $this->sec2hms($value);
}
public function getStateAttribute($value)
{
if (!empty($value))
return trim($value);
return null;
}
/**
* Convert last call attribute to acceptable format
*
* #param $value
* #return string
*/
public function getLastCallAttribute($value)
{
$data = explode("\n", $value);
$result = "";
$i = 0;
$len = count($data) - 1;
foreach ($data as $item) {
$item = str_replace("\r", "", $item);
$delimiter = "</br>";
if ($i == $len)
$delimiter = "";
if (empty($item) || (trim($item) == "No calls yet")) {
$result .= "No calls yet$delimiter";
} else {
$result .= $this->sec2hms($item) . " min. ago $delimiter";
}
$i++;
}
return $result;
}
public function getStationAttribute($value)
{
return str_replace("\r\n", "</br>", $value);
}
private function sec2hms($sec, $padHours = FALSE)
{
$timeStart = Carbon::now();
$timeEnd = Carbon::now()->addSeconds(intval($sec));
return $timeStart->diff($timeEnd)->format('%H:%I:%S');
}
}
is a AmiApiController
class AmiApiController extends Controller
{
public function fetchDashboardData()
{
$this->updateQueueState();
$activeCallers = ActiveCaller::with('Employee')
->where('old', true)
->orderBy('queue')
->orderBy('employee_id')
->orderBy('station', 'asc')
->get();
$waitingList = WaitingList::where('old', false)->get();
$waitingList = $waitingList->unique('client_id');
$charts = Chart::all()->toArray();
$chartFormatData = [
'Total' => [],
'Callers' => [],
'Queues' => [],
];
foreach ($charts as $key => $chart) {
$charts[$key]['data'] = json_decode($chart['data'], 1);
$chartFormatData[$chart['name']]['total'] = 0;
foreach ($charts[$key]['data']['statistic'] as $datum) {
// if ($datum[0] === 'Effort')
// continue;
$chartFormatData[$chart['name']]['label'][] = $datum[0];
$chartFormatData[$chart['name']]['data'][] = $datum[1];
$chartFormatData[$chart['name']]['name'] = $chart['name'];
}
$chartFormatData[$chart['name']]['total'] = array_sum($chartFormatData[$chart['name']]['data']);
// $chartFormatData[$chart['name']]['label'] = array_reverse($chartFormatData[$chart['name']]['label']);
}
return response()->json([
'activeCallers' => $activeCallers,
'charts' => $chartFormatData,
'waitingList' => $waitingList
], 200);
}
this is where we begin to check if we can update the database at this time
/**
* Check whether the database can be updated at this time
*
* - Returns True if no updates are currently being made to the database
* and the latest update was less than 5 seconds later
* -
Returns True if the update already occurs for more than 15 seconds
*
* - Returns False if an update is already in the database
* -
Returns False if the last update was within the last 5 seconds
*
* If the parameter in $ json is passed true (by default)
* the method returns the answer in JSON format
*
* If the parameter is passed false to $ json
* method returns a php-shne Boolean value
*
* #param bool $json
* #return bool|\Illuminate\Http\JsonResponse
*/
public function canWeUpdate($json = true)
{
$result = ['return' => null, 'msg' => null];
$isUpdating = Configuration::where('key', 'is_ami_data_updating')->first();
if (is_null($isUpdating)) {
Configuration::create(['key' => 'is_ami_data_updating', 'value' => 0]);
}
if ($isUpdating->value == true) {
// if an update is currently in progress
$checkingDate = Carbon::now()->addSeconds(-10);
if ($isUpdating->updated_at < $checkingDate) {
// if the update is longer than 15 seconds, we will cancel this update
$isUpdating->update(['value' => false]);
$result['return'] = true;
$result['msg'] = "Old update in database";
} else {
// if the update is less than 15 seconds, we cannot update again
$result['return'] = false;
$result['msg'] = "CURRENTLY UPDATE";
}
} else if ($isUpdating->updated_at > Carbon::now()->addSeconds(-3)) {
// if the last update was less than 5 seconds ago, we cannot update
$result['return'] = false;
$result['msg'] = "TOO EARLY";
} else {
//if the last update was more than 5 seconds ago, we allow the update
$result['return'] = true;
$result['msg'] = "OK";
}
if ($json)
return $this->simpleResponse($result['return'], $result['msg']);
return $result['return'];
}
is a method fot check if new data is in the database
/**
* A method to check if new data is in the database
*
* Returns True if validation time is less than database update time
* Returns False if validation time is longer than database update time
* Returns False if there is no data in the database
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function checkForNewData(Request $request)
{
$date = new Carbon($request->last_call);
$lastRecord = ActiveCaller::latest()->first();
if (is_null($lastRecord))
return $this->simpleResponse(false);
if ($date < $lastRecord->updated_at) {
return $this->simpleResponse(true);
} else
return $this->simpleResponse(false);
}
/**
* Method for loading table data
*
* Agents - information about active numbers in the PBX in all queues
* Waiting - information about numbers in standby mode
*
* #return \Illuminate\Http\JsonResponse
*/
public function renderAgentTable()
{
$agents = ActiveCaller::with('Employee')
->where('old', true)
->orderBy('queue')
->orderBy('station', 'asc')
->get();
$waitingList = WaitingList::all();
$agentsTable = View::make('dashboard.render.agent-table', ['agents' => $agents]);
$waitingTable = View::make('dashboard.render.waiting-list-table', ['waitingList' => $waitingList]);
$result =
[
'agents' => $agentsTable->render(),
'waiting' => $waitingTable->render(),
];
$result = array_merge($result, $this->renderDashboardChart(new Request()));
return response()->json($result);
}
/**
* Method for updating data from AMI
*
* updating data for ActiveCaller
* updating data for WaitingList
*/
public function updateQueueState()
{
if (!$this->canWeUpdate(false)) {
// dd("We can't update (large check)");
return;
}
$lastUpdateTime = ActiveCaller::latest()->first();
if ($lastUpdateTime != null)
if ($lastUpdateTime->created_at > Carbon::now()->addSeconds(-3)) {
// dd("We can't update (small check)");
return;
}
// we notice the launch of the update in the database
$isAmiDataUpdating = Configuration::where('key', 'is_ami_data_updating')->first();
$isAmiDataUpdating->update(['value' => true]);
$this->ClearOldRecords();
$queues = Queue::where('on_dashboard', '=', '1')->get()->toArray();
// we go through all the queues that are available in AMI
foreach ($queues as $queue) {
$command = new AMIQueueMemberState($queue['name']);
// we get a list of numbers and a waiting list of calls
$response = $command->handle();
$agents = $response['agents'];
$callers = $response['callers'];
//convert the waiting list to PeerList
$peerList = PeerInfo::hydrate($agents);
$employees = new Collection();
foreach ($callers as $caller) {
$caller['queue'] = $queue['name'];
WaitingList::create($caller);
}
$peerList->each(function (PeerInfo $peer) use ($employees) {
$record = Record
::where('phone', 'like', '%' . $peer->name . '%')
->where('end_date', null)
->get()->first();
$data = null;
if ($record != null) {
// check if this user already has an entry in active_callers (not old)
$active = ActiveCaller
::where('employee_id', $record['employee_id'])
->where('old', false)
->get()->first();
// if so, add him another number and
// we move on to the next iteration
if ($active != null) {
if ($this->HandleSingleActive($active, $peer->name, $peer->last_call))
return;
}
$peer->station = $record['station_name'];
$peer->employee_id = $record['employee_id'];
$a = collect($peer->toArray());
$data = $a->except(['name', 'pause'])->toArray();
$data['station'] = "$peer->station | $peer->name";
} else {
$peer->station = "- | $peer->name";
$a = collect($peer->toArray());
$data = $a->except(['name', 'pause'])->toArray();
}
ActiveCaller::create($data);
});
}
$this->updateDashboardChart();
$isAmiDataUpdating->update(['value' => false]);
}
I have been getting back into Codeigniter as support was picked up by BCIT. I have a problem with ci_sessions and the database driver which is regenerating the encrypted session ID and storing new data in my database on every page refresh. I'm so frustrated right now! I have both secure file storage and database for both common drivers. I want to use both or either but the effect on my application is the same whether I am using a database or files. The ci_session keeps refreshing and it is not ideal for logins, registration or any account type. Please help me see what I am doing wrong? Much appreciation granted in advance.
Config:
$config['sess_driver'] = 'database';
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 7200;
$config['sess_save_path'] = 'users';
$config['sess_match_ip'] = FALSE;
$config['sess_time_to_update'] = 300;
$config['sess_regenerate_destroy'] = FALSE;
Controllers:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* User Management class created by CodexWorld
*/
class Limousers extends CI_Controller {
function __construct() {
parent::__construct();
$this->load->library('form_validation');
$this->load->model('user');
}
/*
* User account information
*/
public function account(){
print_r($_SESSION);
$data = array();
print_r($this->session->userdata());
if($this->session->userdata('isUserLoggedIn')){
$data['user'] = $this->user->getRows(array('id'=>$this->session->userdata('userId')));
//load the view
$this->load->view('limousers/account', $data);
}else{
redirect('limousers/login');
exit;
}
}
/*
* User login
*/
public function login(){
print_r($_SESSION);
if($this->session->userdata('isUserLoggedIn'))
{
print_r($this->session->userdata);
redirect('limousers/account');
exit;
}
$data = array();
if($this->session->userdata('success_msg')){
$data['success_msg'] = $this->session->userdata('success_msg');
$this->session->unset_userdata('success_msg');
}
if($this->session->userdata('error_msg')){
$data['error_msg'] = $this->session->userdata('error_msg');
$this->session->unset_userdata('error_msg');
}
if($this->input->post('loginSubmit')){
$this->form_validation->set_rules('email', 'Email', 'required|valid_email');
$this->form_validation->set_rules('password', 'password', 'required');
if ($this->form_validation->run() == true) {
$con['returnType'] = 'single';
$con['conditions'] = array(
'email'=>$this->input->post('email'),
'password' => md5($this->input->post('password')),
'status' => '1'
);
$checkLogin = $this->user->getRows($con);
if($checkLogin){
$this->session->set_userdata('name',$con['conditions']['email']);
$this->session->set_userdata('isUserLoggedIn',TRUE);
$this->session->set_userdata('userId',$checkLogin['id']);
redirect('limousers/account');
exit;
}else{
$data['error_msg'] = 'Wrong email or password, please try again.';
}
}
}
//load the view
$this->load->view('limousers/login', $data);
}
/*
* User registration
*/
public function registration(){
print_r($_SESSION);
$data = array();
$userData = array();
if($this->input->post('regisSubmit')){
$this->form_validation->set_rules('name', 'Name', 'required');
$this->form_validation->set_rules('email', 'Email', 'required|valid_email|callback_email_check');
$this->form_validation->set_rules('password', 'password', 'required');
$this->form_validation->set_rules('conf_password', 'confirm password', 'required|matches[password]');
$userData = array(
'name' => strip_tags($this->input->post('name')),
'email' => strip_tags($this->input->post('email')),
'password' => md5($this->input->post('password')),
'gender' => $this->input->post('gender'),
'phone' => strip_tags($this->input->post('phone'))
);
if($this->form_validation->run() == true){
$insert = $this->user->insert($userData);
if($insert){
$this->session->set_userdata('success_msg', 'Your registration was successfully. Please login to your account.');
redirect('limousers/login');
exit;
}else{
$data['error_msg'] = 'Some problems occured, please try again.';
}
}
}
$data['user'] = $userData;
//load the view
$this->load->view('limousers/registration', $data);
}
/*
* User logout
*/
public function logout(){
$this->session->unset_userdata('isUserLoggedIn');
$this->session->unset_userdata('userId');
$this->session->sess_destroy();
redirect('limousers/login');
exit;
}
/*
* Existing email check during validation
*/
public function email_check($str){
$con['returnType'] = 'count';
$con['conditions'] = array('email'=>$str);
$checkEmail = $this->user->getRows($con);
if($checkEmail > 0){
$this->form_validation->set_message('email_check', 'The given email already exists.');
return FALSE;
} else {
return TRUE;
}
}
}
Models:
<?php if ( ! defined('BASEPATH')) exit('No direct script access
allowed');
class User extends CI_Model{
function __construct() {
$this->userTbl = 'users';
}
/*
* get rows from the users table
*/
function getRows($params = array()){
$this->db->select('*');
$this->db->from($this->userTbl);
//fetch data by conditions
if(array_key_exists("conditions",$params)){
foreach ($params['conditions'] as $key => $value) {
$this->db->where($key,$value);
}
}
if(array_key_exists("id",$params)){
$this->db->where('id',$params['id']);
$query = $this->db->get();
$result = $query->row_array();
}else{
//set start and limit
if(array_key_exists("start",$params) &&
array_key_exists("limit",$params)){
$this->db->limit($params['limit'],$params['start']);
}elseif(!array_key_exists("start",$params) &&
array_key_exists("limit",$params)){
$this->db->limit($params['limit']);
}
$query = $this->db->get();
if(array_key_exists("returnType",$params) &&
$params['returnType'] == 'count'){
$result = $query->num_rows();
}elseif(array_key_exists("returnType",$params) &&
$params['returnType'] == 'single'){
$result = ($query->num_rows() > 0)?$query- >row_array():FALSE;
}else{
$result = ($query->num_rows() > 0)?$query->result_array():FALSE;
}
}
//return fetched data
return $result;
}
/*
* Insert user information
*/
public function insert($data = array()) {
//add created and modified data if not included
if(!array_key_exists("created", $data)){
$data['created'] = date("Y-m-d H:i:s");
}
if(!array_key_exists("modified", $data)){
$data['modified'] = date("Y-m-d H:i:s");
}
//insert user data to users table
$insert = $this->db->insert($this->userTbl, $data);
//return the status
if($insert){
return $this->db->insert_id();
}else{
return false;
}
}
}
I have the UsersFixture with three records.
The test methods first() and second(), which both are before guest_can_login(), pr's show "Joe", "Joe", as expected. But with test method third(), which comes after guest_can_login(), I get notice error: trying to get property of non-object.
So, for a reason, something in the guest_can_login() breaks the rest of the test methods. I have tried by making a duplicate of guest_can_login() as well.
I think it is strange, as tearDown should "reset" everything after each test. I'm out of ideas. And after reading the Cakephp Testing docs, I haven't been able to solve it.
Any suggestions to help me solve this is much appreciated.
Code below (gist if you prefer: https://gist.github.com/chris-andre/2eb3ad053073caf4f1c81722428a900b):
public $fixtures = [
'app.users',
'app.tenants',
'app.roles',
'app.roles_users',
];
public $Users;
public function setUp()
{
parent::setUp();
$config = TableRegistry::getTableLocator()->exists('Users') ? [] : ['className' => UsersTable::class];
$this->Users = TableRegistry::getTableLocator()->get('Users', $config);
}
/**
* tearDown method
*
* #return void
*/
public function tearDown()
{
unset($this->Users);
TableRegistry::clear();
parent::tearDown();
}
/** #test */
public function guest_can_register()
{
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->configRequest([
'headers' => [
'host' => 'timbas.test'
]
]);
$data = [
'email' => 'chris#andre.com',
'first_name' => 'Christian',
'last_name' => 'Andreassen',
'password' => '123456',
'tenant' => ['name' => 'Test Company AS', 'domain' => 'testcomp', 'active' => true],
'active' => true
];
$this->post('/register', $data);
$this->assertResponseSuccess();
$this->assertRedirect(['controller' => 'Users', 'action' => 'login', '_host' => 'testcomp.timbas.test']);
$user = $this->Users->find()
->contain(['Tenants', 'Roles'])
->where(['Users.email' => 'chris#andre.com'])
->first();
}
/** #test */
public function first()
{
$users = $this->Users->find()->first();
pr($users->first_name);
}
/** #test */
public function second()
{
$users = $this->Users->find()->first();
pr($users->first_name);
}
/** #test */
public function guest_can_login()
{
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->configRequest([
'headers' => [
'host' => 'testcomp.timbas.test'
]
]);
$data = [
'email' => 'chris#andre.com',
'first_name' => 'Christian',
'last_name' => 'Andreassen',
'password' => '123456',
'tenant' => ['name' => 'Test Company AS', 'domain' => 'testcomp', 'active' => true],
'active' => true,
'roles' => ['_ids' => [ADMINISTRATOR_ROLE_ID]]
];
$user = $this->Users->newEntity($data, [
'associated' => ['Tenants', 'Roles']
]);
$this->Users->save($user);
$getNewUser = $this->Users->find()
->contain(['Roles'])
->where(['Users.email' => 'chris#andre.com'])
->first()
->toArray();
// pr($getNewUser->id);
$this->post('/users/login', [
'email' => 'chris#andre.com',
'password' => '123456'
]);
$this->assertSession($getNewUser, 'Auth.User');
}
/** #test */
public function third()
{
$users = $this->Users->find()->first();
pr($users->first_name);
}
EDIT 2018-08-06:
Users::register() is a global context, I cannot be accessed from url with subdomain. E.g. tenant1.domain.com/register will throw a badRequest, while domain.com/register is a valid url. On registration success, user is forwarded to login from right url. Login-url = Tenants.domain + domain + suffix, e.g. tenant1.domain.com. When user is on the tenant scope (url with subdomain), the Tenants.id where Tenants.domain = tenant1, will be added to the where clause in all queries for the models having the behavior attached.
Now, what happens in third() is that the tenant_id from the newly created Tenant in guest_can_login() is added to the query, which means the test "is still on the tenant scope" when third() is run. That is the problem.
The other problem is that setUp() is called on all test methods but third(). testDown() is called on every test methods.
App\Middleware\TenantMiddleware.php:
use InstanceConfigTrait;
/**
* Default config.
* Options:
* - globalScope: tells the middleware what controller and action tenant scope is not being used
* Example
* 'globalScope' => [
* 'Pages' => ['*'], // All actions in PagesController is global
* 'Users' => ['register'] // Register action in UsersController is global
* ]
* #var array
*/
protected $_defaultConfig = [
'globalScope' => [
'Users' => ['register'],
'Landing' => ['*'],
'Pages' => ['*']
],
];
public function __construct($config = [])
{
if (!isset($config['primaryDomain'])) {
$config['primaryDomain'] = Configure::read('Site.domain');
}
$this->setConfig($config);
}
/**
* Invoke method.
*
* #param \Cake\Http\ServerRequest $request The request.
* #param \Psr\Http\Message\ResponseInterface $response The response.
* #param callable $next Callback to invoke the next middleware.
* #return \Psr\Http\Message\ResponseInterface A response
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
// Get subdomains
$subdomains = $request->subdomains();
// If subdomains not empty, the first is always the tenants domain
$subdomain = !empty($subdomains) ? $subdomains[0] : '';
Tenant::setDomain($subdomain);
// Get params of current request
$params = $request->getAttribute('params');
$controller = $params['controller'];
$action = $params['action'];
// Set tenantScope as default
Tenant::setScope('tenant');
$globalScope = $this->getConfig('globalScope');
// If Controller and action is a global scope
if (array_key_exists($controller, $globalScope)) {
if (in_array($action, $globalScope[$controller]) || in_array('*', $globalScope[$controller])) {
Tenant::setScope('global');
}
}
if (
(Tenant::getScope() === 'tenant' && Tenant::tenant() === null)
|| (Tenant::getDomain() === '' && Tenant::getScope() === 'tenant')
|| (Tenant::getDomain() !== '' && Tenant::getScope() === 'global')
) {
throw new NotFoundException('The page you are looking for does not exists.');
}
$primaryDomain = $this->getConfig('primaryDomain');
if (array_key_exists($controller, $globalScope)) {
if (in_array($action, $globalScope[$controller]) && Tenant::getScope() === 'global') {
}
}
return $next($request, $response);
}
App\Model\Behavior\TenantScopeBehavior.php:
protected $_table;
/**
* Default configuration.
*
* #var array
*/
protected $_defaultConfig = [];
public function __construct(Table $table, array $config = [])
{
parent::__construct($table, $config);
}
public function beforeFind(Event $event, Query $query, ArrayObject $options)
{
$model = $this->_table->getAlias();
$foreig_key = 'tenant_id';
if (!isset($options['skipTenantCheck']) || $options['skipTenantCheck'] !== true) {
if (Tenant::getScope() === 'tenant') {
if ($model === 'Tenants') {
$query->where(['Tenants.id' => Tenant::tenant()->id]);
} else {
$query->where([$model . '.' . $foreig_key => Tenant::tenant()->id]);
}
}
}
return $query;
}
public function beforeSave(Event $event, Entity $entity, $options)
{
if (Tenant::getScope() === 'tenant') {
if ($entity->isNew()) {
$entity->tenant_id = Tenant::tenant()->id;
} else {
// Check if current tenant is owner
if ($this->_table->getAlias() === 'Tenants') {
if ($entity->id != Tenant::tenant()->id) {
throw new BadRequestException();
}
} else {
if ($entity->tenant_id != Tenant::tenant()->id) {
throw new BadRequestException();
}
}
}
}
return true;
}
public function beforeDelete(Event $event, Entity $entity, $options)
{
if (Tenant::getScope() === 'tenant') {
if ($entity->tenant_id != Tenant::tenant()->id) { //current tenant is NOT owner
throw new BadRequestException();
}
}
return true;
}
App\Tenant\Tenant.php:
/**
* $_domain will be empty or comtain the domain (subdomain from url)
* #var string can be empty
*/
protected static $_domain;
/**
* $_scope shall be 'global' or 'tenant'.
* #var string
*/
protected static $_scope;
/**
* #var null|object \App\Model\Entity\Tenant
*/
protected static $_tenant;
/**
* Gets domain from $_domain and returns the string
* #return string
*/
public static function getDomain()
{
return self::$_domain;
}
/**
* Set the tenant scope domain. Will be set in the TenantMiddleware, and shall not be set anywhere else
* #param string $domain
* #return string empty or with domain
*/
public static function setDomain($domain)
{
self::$_domain = $domain;
}
/**
* Tenant method
* Return the object \App\Model\Table\Tenants ro null
* #return type
*/
public static function tenant()
{
$tenant = static::_getTenant();
return $tenant;
}
protected static function _getTenant()
{
if (self::$_tenant === null) {
$cachedTenants = Cache::read('tenants');
if($cachedTenants !== false) {
// do something
}
$tenantsTable = TableRegistry::get('Tenants');
$tenant = $tenantsTable->find('all', ['skipTenantCheck' => true])
->where(['Tenants.domain' => self::getDomain()])
->where(['Tenants.active' => true])
->first();
self::$_tenant = $tenant;
}
return self::$_tenant;
}
public static function getScope()
{
return self::$_scope;
}
/**
* Description
* #param type $scope
* #return type
*/
public static function setScope($scope)
{
self::$_scope = $scope;
}
I'm using cakephp framework.I want to export a database table of a client download in two formats.One is '.csv', the other is a '.txt'.CSV which I have passed 'csvHelper' resolved.Now I want to know how to export '.txt'.Sorry for my poor English, but I think you'll see what I mean, thanks!
Basically you set the header for the filename, like this:
$this->response->type('Content-Type: text/csv');
$this->response->download('myfilename.txt');
Here are some functions I put in my appController, so that any controller can output a CSV file if required:
/**
* Flattens the data that is returned from a find() operation, and puts it into CSV format
* #param $data
* #return string
*/
public function _arrayToCsvFile($data){
$flattenedData = array();
$exportKeyPair = array();
foreach($data as $datumKey => $datumDetails){
$flattenedDatum = Hash::flatten($datumDetails, '.');
$flattenedData[] = $flattenedDatum;
// Find all keys
if($datumKey == 0){
$exportKeys = array_keys($flattenedDatum);
$exportKeyPair = array_combine($exportKeys, $exportKeys);
}
else {
$datumKeys = array_keys($flattenedDatum);
$datumKeyPair = array_combine($datumKeys, $datumKeys);
// Add the datum keys to the exportKeyPair if it's not already there
$exportKeyPair = array_merge($exportKeyPair, $datumKeyPair);
}
}
$exportKeyMap = array();
foreach($exportKeyPair as $exportKey => $exportValue){
$exportKeyMap[$exportKey] = "";
}
$outputCSV = '';
$outputCSV .= $this->_arrayToCsvLine($exportKeyPair);
foreach($flattenedData as $flattenedDatumKey => $flattenedDatumDetails){
// Add any extra keys
$normalisedDatumDetails = array_merge($exportKeyMap, $flattenedDatumDetails);
$outputCSV .= $this->_arrayToCsvLine($normalisedDatumDetails);
}
return $outputCSV;
}
/**
* arrayToCsvLine function - turns an array into a line of CSV data.
*
* #access public
* #param mixed $inputLineArray the input array
* #param string $separator (default: ")
* #param string $quote (default: '"')
* #return string
*/
function _arrayToCsvLine($inputLineArray, $separator = ",", $quote = '"') {
$outputLine = "";
$numOutput = 0;
foreach($inputLineArray as $inputLineKey => $inputLineValue) {
if($numOutput > 0) {
$outputLine .= $separator;
}
$outputLine .= $quote . str_replace(array('"', "\n", "\r"),array('""', "", ""), $inputLineValue) . $quote;
$numOutput++;
}
$outputLine .= "\n";
return $outputLine;
}
/**
* Serves some CSV contents out to the client
* #param $csvContents
* #param array $options
*/
public function _serveCsv($csvContents, $options = array()){
$defaults = array(
'modelClass' => $this->modelClass,
'fileName' => null
);
$settings = array_merge($defaults, $options);
if(empty($settings['fileName'])){
$settings['fileName'] = strtolower( Inflector::pluralize( $settings['modelClass'] ) ) . '_' . date('Y-m-d_H-i') . '.csv';
}
$this->autoRender = false;
$this->response->type('Content-Type: text/csv');
$this->response->download($settings['fileName']);
$this->response->body($csvContents);
}
Now in any controller you can do this (note that you can pass the filename to _serveCsv if required):
/**
* admin_export_csv method
*
* #return void
*/
public function admin_export_csv() {
$this->Order->recursive = 0;
$conditions = array();
$orders = $this->Order->find('all', array('conditions' => $conditions));
$csvContents = $this->_arrayToCsvFile($orders); // Function in AppController
$this->_serveCsv($csvContents, array('filename' => 'export.txt')); // Function in AppController
}
you can use
$this->RequestHandler->respondAs('txt'); to output the correct header.
Please not the header is not set when DEBUG is greater than 2.
And you will still have to build the controller action and set view as ususal.
Is there more optimal and shorter way to get nodes with certain conditions?
$query = new EntityFieldQuery;
$result = $query
->entityCondition('entity_type', 'node')
->propertyCondition('type', $node_type)
->propertyCondition('title', $title)
->fieldCondition('field_number', 'value', '1', '=');
->propertyCondition('status', 1, '=')
->execute();
// $result['node'] contains a list of nids where the title matches
if (!empty($result['node']) {
// You could use node_load_multiple() instead of entity_load() for nodes
$nodes = entity_load('node', array_keys($result['node']));
}
$query_two = new EntityFieldQuery;
$result_two = $query_two
->entityCondition('entity_type', 'node')
->propertyCondition('type', $node_type)
->propertyCondition('title', $title)
->fieldCondition('field_number', 'value', '2', '=');
->propertyCondition('status', 1, '=')
->execute();
// $result_two['node'] contains a list of nids where the title matches
if (!empty($result_two['node']) {
// You could use node_load_multiple() instead of entity_load() for nodes
$nodes_two = entity_load('node', array_keys($result_two['node']));
}
Well, you certainly could use ->fieldCondition('field_number', 'value', array(1, 2)), but other than that, not that I know of (and I wrote EntityFieldQuery). Even if you were to rewrite this to an SQL-storage only query, it would not be much simpler.
You do not need to specify = as the operator and you do not need to specify IN either, they are defaults for a scalar / array value.
I recently wrote a wrapper for EntityFieldQuery, since i just use it too much. Then the way I call it becomes to, the result can be an id or an array of ids. Hope this makes sense.
$ids = qplot_api_find_nodes2(
array(
'type' => 'content',
'field_content_project' => array('target_id', 10, '='),
),
array(
'created' => 'ASC'
),
TRUE
);
/**
* Returns node nid(s) with filters and sorts.
*
* #param array $conds
* Condition entries, there're three different type of conditions
* 1. prefixed with entity_, ex. 'entity_type' => 'node'
* 2. prefixed with field_, ex. 'field_project',
* two formats allowed, simple version 'field_tag' => 'abc',
* or long version, 'field_tag' => array('target_id', 11, '=')
* 3. no prefix or other prefix, 'title' => 'abc'
* Default $conds contains 'entity_type' => 'node' entry.
*
* #param array $sorts
* Sort entiries, there're two different type of sorts
* 1. prefixed with field_, ex. 'field_tag' => array('target_id', 'ASC')
* 2. no prefix or other prefix, 'title' => 'ASC'
* Default $sorts are empty
*
* #param bool $all
* If all matching nid are returned, or just the first one, default FALSE
*
* #return int
* The nid for the supplied id or 0 if not found.
* Or array of nids if $all = TRUE
*
* #author Fang Jin <windmaomao#gmail.com>
*/
function qplot_api_find_nodes2($conds, $sorts = NULL, $all = FALSE) {
$conds = array_merge(array('entity_type' => 'node'), $conds);
if (empty($sorts)) {
$sorts = array();
}
$query = new EntityFieldQuery();
// apply condition to query
foreach ($conds as $key => $value) {
$splits = explode('_', $key);
$type = $splits[0];
if (count($splits) == 1) {
$type = 'property';
}
switch ($type) {
case 'entity':
$query->entityCondition($key, $value);
break;
case 'field':
if (is_array($value)) {
$property = isset($value[1]) ? $value[0] : 'value';
$assigned = isset($value[1]) ? $value[1] : $value[0];
$operator = isset($value[2]) ? $value[2] : '=';
$query->fieldCondition($key, $property, $assigned, $operator);
} else {
$query->fieldCondition($key, 'value', $value);
}
break;
// rest of them are all property
default:
$query->propertyCondition($key, $value);
break;
}
}
// apply sort to query
foreach ($sorts as $key => $value) {
$splits = explode('_', $key);
$type = $splits[0];
if (count($splits) == 1) {
$type = 'property';
}
switch ($type) {
case 'field':
$query->fieldOrderBy($key, $value[0], $value[1]);
break;
default:
$query->propertyOrderBy($key, $value);
break;
}
}
$result = $query->execute();
$ctype = $conds['entity_type'];
if (!empty($result[$ctype])) {
$keys = array_keys($result[$ctype]);
if ($all) {
return $keys;
}
else {
return $keys[0];
}
} else {
if ($all) {
return array();
} else {
return 0;
}
}
}