CakePHP model and querying troubles - mysql

I'm using CakePHP 2.3.8 and I'm having trouble getting Cake to properly search for a value. It appears not to be case sensitive. I'm searching for 'User.id' and the query result it shows up as 'user.id'
users table
id | username | password | email | created
I'm trying to find the date a user was created in my ReservationController
$this->loadmodel('User');
$date = $this->User->find('first',array(
'conditions' => array(
'User.id' => $id //note: 'id' => $id gives the same results
)
));
I get the following error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.id' in 'where clause'
SQL Query: SELECT `User`.`created` FROM `TestDB`.`users` AS `User` WHERE `user`.`id` = 1 LIMIT 1
When I copy the query into PHPMyadmin and change 'user.id' to 'User.id' it then works. Why is Cake making the u lowercase even though I capitalize it in my query? If I change it to 'Users.id' cake will then search with an uppsercause U and adds the s, but that's not what I want.
I tried adding a primary key to my user model with public $primaryKey = 'id'; but that didn't do anything. Currently, I don't have any references for primary key in my User model so I'm not sure where/why it's deciding to search for 'user.id' even though I specifically reference 'User.id' in my search. In fact, the only thing in my user model is for form validation.

You do not need to Add modelName in Query if its for Same Model.. Retriving data
$this->loadModel('User');
$date = $this->User->find('first',array(
'conditions' => array(
'id' => $id
)
));

Related

Alias for table

I have two tables. The first - Product, the second - Category. They contain fields with the same name - 'name'.
In model Product I added following code:
public function getCategory(){
return $this->hasOne(Category::className(), ['id' => 'cat_id']);
}
I need to show in GridView the column from table Category. I added following code for this in the model ProductSearch:
$query->joinWith(['category' => function($query) { $query->from(['cat' => 'category']); }]);
This code adds the alias cat for the table Category.
After that I got an error:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'name' in where clause is ambiguous
The SQL being executed was: SELECT COUNT(*) FROM `product` LEFT JOIN `category` `cat` ON `product`.`cat_id` = `cat`.`id` WHERE `name` LIKE '%aasdadadsdgdgdg%'
Error Info: Array
(
[0] => 23000
[1] => 1052
[2] => Column 'name' in where clause is ambiguous
)
How can I add the alias for the table Product?
Open your ProductSearch model, navigate to the search($params) method. Below you should see the filtration part:
$query->andFilterWhere(['like', 'name', $this->name])
fix the ambigous part by writing table name product to that line.
$query->andFilterWhere(['like', 'product.name', $this->name])
or..
$query->andFilterWhere(['like', self::tableName() . '.name', $this->name])
This'll giving precise info that name should be queried from product.name table.
The interesting part is that you don't get the error until you join the Category table.
Imho, it's the worst to find this errors as it seems like everything is working, until search functionality is used.

Using limit and offset in subquery in Zend framework 2

I have two tables: users and usermeta. The table usermetahas 4 columns: id, user_id, meta_key and meta_value. A user can have many meta data.
I want to get the groups of the first 10 users. So I create a SQL query in Zend framework 2:
$coreSelect = $sql->select()
->from('users')
->limit(10)
->offset(0);
$select = $sql->select()
->from(array('u' => $coreSelect))
->join('usermeta',
'u.user_id = usermeta.user_id',
array(
'meta_key' => 'meta_key',
'meta_value' => 'meta_value',
),
Select::JOIN_LEFT
);
When execute this query, it show up a SQL syntax error. The SQL query string manipulated by Zend framework is like this:
SELECT u.*
FROM (
SELECT * FROM users LIMIT '10' OFFSET '0') AS u
...
It means that Zend framework has added quotes into offset and limit value and it makes the syntax error.
Can anyone please help me to resolve this problem?
This should help you:
http://www.maltblue.com/tutorial/zend-db-sql-creating-joins-and-unions-with-ease
Something that interests you, towards the end, but read all of it is useful.

Selecting records from DB with Zend using distinct but two fields

I need to select two fields from a table (with Zend 1.12) -- id and sender name -- from a database, but I want to select only the unique sender names as many of them are duplicated. Here is my code:
$objSelect = $db->select()
->distinct()
->from('tbl_sc_invites', array('id', 'sender_name'), 'sender_name')
->order('sender_name ASC')
;
But I get the error Mysqli prepare error: Table 'sender_name.tbl_sc_invites' doesn't exist
How do I do that? I need to have both id and sender_name returned from the database so I can create a dropdown.
Something like this?
$objSelect = $db->select()
->distinct()
->from('tbl_sc_invites', array('id', 'sender_name'))
->order('sender_name ASC');
Otherwise if you don't care about which id you get back you could use GROUP BY
$objSelect = $db->select()
->distinct()
->from('tbl_sc_invites', array('id', 'sender_name'))
->order('sender_name ASC')
->group('sender_name');

CakePHP 2.2.4: Why does this Union $this->Model->query not work?

I'm in the view action of my PhotosController.php. What I want to do is given the id of the current photo I am viewing, create a carousel of photos containing the two photos before and two photos after the current photo with the current photo in the middle (5 in total).
I was pointed to this solution but I can't seem to convert it to CakePHP using $this->Photo->query.
My controller
$this->set('photos', $this->Photo->query("
SELECT id, file FROM photos WHERE id <= $id AND page_id = $page_id ORDER BY id DESC LIMIT 3
UNION ALL
SELECT id, file FROM photos WHERE id > $id AND page_id = $page_id ORDER BY id ASC LIMIT 2
"));
Unfortunately, when I don't see anything when I turn debugging on. id, file, and page_id are all columns in the photos table. Both #id and $page_id are passed to the action from the router. Is my syntax wrong?
EDIT: If I remove the UNION ALL and the second SELECT statement, then the query works fine so it's not an issue with the model not being loaded because it is.
EDIT (workaround): For now I'm doing two queries which is not ideal.
$this->set('photos_before', $this->Photo->find('all', array(
'conditions' => array(
'Photo.page_id' => $page_id,
'Photo.id <' => $id
),
'order' => array('Photo.id ASC'),
'limit' => 2
)));
$this->set('photos_after', $this->Photo->find('all', array(
'conditions' => array(
'Photo.page_id' => $page_id,
'Photo.id >' => $id
),
'order' => array('Photo.id ASC'),
'limit' => 2
)));
I have a contain before hand to only return the fields and associated models I need.
Below is what I want to be displayed and it currently works using the two queries above but I am hoping this can be achieved with a single, Cake-friendly query
My guess is that your original query is invalid SQL. Afaik UNIONS cannot contain multiple 'order by' clauses. As a workaround you may consider to rewrite it to use subqueries like this:
SELECT * FROM (SELECT id, file FROM photos WHERE id <= $id AND page_id = $page_id ORDER BY id DESC LIMIT 3) AS suba
UNION ALL
SELECT * FROM (SELECT id, file FROM photos WHERE id > $id AND page_id = $page_id ORDER BY id ASC LIMIT 2) AS subb
Although I serious think a query like this is far from optimal. Of course, I don't know the way your application works, but it seems that a standard pagination query, with a OFFSET/LIMIT is a more logical approach.
Please take my comment below your question into account; using model->query does NOT automatically handle sanitisation/escaping to prevent SQL injections!
You have to load model as
$this->loadModel('Photo');
Before executing query.
You should create a VIEW in MySQL and then use that as a model, and do a traditional CakePHP find on that.
Read up on creating views in MySQL and then create a model based on that view name.

CakePHP & MySQL - Using find('all') with GROUP for one field and MAX for another field

I have a MySQL table with 3 columns (thread_id, message_id, message). Along the lines of the solution found under the "Example using GROUP BY" in this link, I want my query to GROUP BY thread_id, but return the line of of the highest message_id (instead of default lowest) for each thread_id. I then want a nicely formatted array with lines/items just like you get for less complex find operations in CakePHP along the lines of $array[index]['Model']['field']. Using the following CakePHP syntax:
$this->Model->find('all', array(
'fields' => array('MAX(Model.message_id) as message_id', 'Model.thread_id', 'Model.message'),
'group => 'Model.thread_id'
));
Now, unfortunately I am not getting that nicely formatted array. Instead I get an array which looks something like:
Array ( [0] => Array ( [0] => Array ( [message_id] => wanted/correct_message_id ) [Model] => Array ( [message] => Message from lowest/unwanted message_id line. [thread_id] => Key from lowest/unwanted message_id line))
Why does the message_id not get hooked onto the [Model] part of the array and why does CakePHP fetch the lowest message_id line and put the message and thread_id into the [Model] part of the array without the message_id column?
I want all thre columns in the [Model] part of the array and I want that line to be the highest message_id for that thread_id per my initial description. Hope this question makes sense.
Virtual fields are really useful for this kind of thing.
class MyModel extends AppModel {
public $virtualFields = array(
'max_message_id' => 'MAX(MyModel.message_id)'
);
}
You can now use max_message_id as if it were a normal field in your table, so you can add it to your find operations.