CakePHP: Retrieve specific table field in controller - cakephp

I am new to Cake and tried to find the best solution to retrieve a specific field belonging to an $id:
This is my view function in my Post controller
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid post', true));
$this->redirect(array('action' => 'index'));
}
$this->set('post', $this->Post->read(null, $id));
}
In the post table, there is a user_id foreign key. I need to retrieve this specific field belonging to this Post $id.
I read about functions as find('All), read() or just drop an unconventional session in the view through:
$session->write('example') = $post['Post']['user_id];
What is the best way to do this, my preference is to retrieve the field in the controller. Thanks!

CakePHP has a field function which should do just that.
$this->Post->id = $id;
$user_id = $this->Post->field('user_id');
For more information on using field, see: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-field
A second option is to use the find function and returning only a few fields if you do not want the entire Post object. Also shown below is using a condition instead of setting the current Post.
$this->Post->find('first', array(
'conditions'=>array('id'=>$id),
'fields'=>array('user_id')
));
More information on find is available at: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html

$this->Post->id = $id;
$this->Session->write('example',$this->Post->field('user_id'));

In CakePHP 3, you can use $this->Model->get() to get the Entity, and then reference the required field directly.
$fieldValue = $this->ModelName->get($id)->fieldName;

Try this one, since I don't know which field(s) you need I provide an example field array set using Magic Find Types:
$fields = ['title', 'body', 'created'];
$record = $this->Post->findById($id, $fields);
or multiple records
$recordSet = $this->Post->findAllByTitle('The title', $fields);
*Note the the second example doesn't make a lot of sense unless there are multiple titles with the name 'The title' in the the posts.title column.

Related

how to post values in cakephp 2.x and show the filtered records in another page

I have designed page in cakephp contains form which input filed name 'id' and submit button. I want to display the data filtered by the 'id' in view page. Please give me an example with code for this.
So you wanna search into a database for this ID and return back all stored data to the view?
First of all,you have to retrieve your data. See here: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
Secondly, you have to use
$this->set('var_name', $var_name_containing_found_data);
and finally you can handle your data into the view by manipulating as you wish the $var_name variable.
Put this action in your controller:
public function your_action($id = null) {//your action
if ($this->request->is('post')) {
$search = $this->YourModel->find('all', array('conditions' => array('id' => $this->request->data['id'])));//assuming id is submitted like you said $_POST['id']
$this->set('search', $search);
}
}
You can access the search variable in your view (your_view.ctp) like this $this->search
assuming your cakephp version is 2.x

sort on array read

In my controller I have
var $uses = array('User','Customer');
then I am using read to call the users
$loggedOutCustomer = $this->User->read(null, $this->Auth->user('id'));
this gives me users and cutsomers that I can use but I want to do a sort on customers name. How can i do that in cake?
You can set the default order in your User model.
If Customer belongsTo User, User hasMany Customer.
In your User model, under the hasMany variable, find the Customer record and add Customer.name to the order array key.
Also, please remove the cakephp version tag that you are not using.
You can also add your sorting options when you're using the find() method of your model.
This can also be defined in the pagination array
Another option would be to use the Containable behavior
Give this a try
$loggedOutCustomer = $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')), 'order' => 'Customer.name ASC'));

How do I update 1 field in CakePHP?

I want a function to alter one field, "is_featured" to 1(true) of Event model of given ID, to mark an event as "Featured".
class EventsController extends AppController{
function feature($id){}
}
you can use saveField to do this
for example
$this->Event->id = $id;
$this->Event->saveField('is_featured', true);
You can perform update in one field by two ways:
$this->Model->id=$id;
$this->Model->saveField("fieldName","value");
OR
$this->Model->updateAll(array("fieldName"=>"value"),array("fieldName"=>"condition"));
in second example, first array will update the value in defined field and second array defines the "WHERE" condition
You can also use set() method
$this->Model->read(null, $id);
$this->Model->set(array(
'fieldname' => 'value',
));
$this->Model->save();
In cakephp 3 to update your data:
Include in your Controller:
use Cake\ORM\TableRegistry;
In your action:
$articlesTable = TableRegistry::get('Articles');
$article = $articlesTable->get(12); // Return article with id 12
$article->title = 'CakePHP is THE best PHP framework!';
$articlesTable->save($article);
Source: http://book.cakephp.org/3.0/en/orm/saving-data.html
You can use this technique to update the field(s)
$this->Event->save($this->request->data, true, array('id', 'is_featured'))
If you don’t want the modified field to be automatically updated when saving some data add 'modified' => false to your $data array
If you don’t pass the id, the model cannot set its primary key and will “add” instead of “edit” the field(s)
You can do this easy way
$this->Event->saveField('username', $user); //Where username is Model field name and $user is value
strangely; sometimes I like to resort for plain old sql: one-liner + no overhead there, makes me sure no callbacks/events get involved (beware this may be not what you want!)
$id = (int) $id;
$this->Event->query("UPDATE events SET is_featured=1 WHERE id=$id");

CakePHP: Can I ignore a field when reading the Model from the DB?

In one of my models, I have a "LONGTEXT" field that has a big dump of a bunch of stuff that I never care to read, and it slows things down, since I'm moving much more data between the DB and the web app.
Is there a way to specify in the model that I want CakePHP to simply ignore that field, and never read it or do anything with it?
I really want to avoid the hassle of creating a separate table and a separate model, only for this field.
Thanks!
Daniel
As #SpawnCxy said, you'll need to use the 'fields' => array(...) option in a find to limit the data you want to retrieve. If you don't want to do this every time you write a find, you can add something like this to your models beforeFind() callback, which will automatically populate the fields options with all fields except the longtext field:
function beforeFind($query) {
if (!isset($query['fields'])) {
foreach ($this->_schema as $field => $foo) {
if ($field == 'longtextfield') {
continue;
}
$query['fields'][] = $this->alias . '.' . $field;
}
}
return $query;
}
Regarding comment:
That's true… The easiest way in this case is probably to unset the field from the schema.
unset($this->Model->_schema['longtextfield']);
I haven't tested it, but this should prevent the field from being included in the query. If you want to make this switchable for each query, you could move it to another variable like $Model->_schemaInactiveFields and move it back when needed. You could even make a Behavior for this.
The parameter fields may help you.It doesn't ignore fields but specifies fields you want:
array(
'conditions' => array('Model.field' => $thisValue), //array of conditions
'fields' => array('Model.field1', 'Model.field2'), //list columns you want
)
You can get more information of retrieving data in the cookbook .
Another idea:
Define your special query in the model:
function myfind($type,$params)
{
$params['fields'] = array('Model.field1','Model.field2',...);
return $this->find($type,$params);
}
Then use it in the controller
$this->Model->myfind($type,$params);
Also try containable behaviour will strip out all unwanted fields and works on model associations as well.
Containable
class Post extends AppModel { <br>
var $actsAs = array('Containable'); <br>
}
where Post is your model?
You can add a beforeFilter function in your Table and add a select to the query
Excample:
public function beforeFind(Event $event, Query $query){
$protected = $this->newEntity()->hidden;
$tableSchema = $event->subject()->schema();
$fields = $tableSchema->columns();
foreach($fields as $key => $name){
if(in_array($name,$protected)){
unset($fields[$key]);
}
}
$query->select($fields);
return $event;
}
In this excample I took the hidden fields from the ModelClass to exclude from result.
Took it from my answer to a simular question here : Hidden fields are still listed from database in cakephp 3

CakePHP HABTM: Editing one item casuses HABTM row to get recreated, destroys extra data

I'm having trouble with my HABTM relationship in CakePHP.
I have two models like so: Department HABTM Location. One large company has many buildings, and each building provides a limited number of services. Each building also has its own webpage, so in addition to the HABTM relationship itself, each HABTM row also has a url field where the user can visit to find additional information about the service they're interested and how it operates at the building they're interested in.
I've set up the models like so:
<?php
class Location extends AppModel {
var $name = 'Location';
var $hasAndBelongsToMany = array(
'Department' => array(
'with' => 'DepartmentsLocation',
'unique' => true
)
);
}
?>
<?php
class Department extends AppModel {
var $name = 'Department';
var $hasAndBelongsToMany = array(
'Location' => array(
'with' => 'DepartmentsLocation',
'unique' => true
)
);
}
?>
<?php
class DepartmentsLocation extends AppModel {
var $name = 'DepartmentsLocation';
var $belongsTo = array(
'Department',
'Location'
);
// I'm pretty sure this method is unrelated. It's not being called when this error
// occurs. Its purpose is to prevent having two HABTM rows with the same location
// and department.
function beforeSave() {
// kill any existing rows with same associations
$this->log(__FILE__ . ": killing existing HABTM rows", LOG_DEBUG);
$result = $this->find('all', array("conditions" =>
array("location_id" => $this->data['DepartmentsLocation']['location_id'],
"department_id" => $this->data['DepartmentsLocation']['department_id'])));
foreach($result as $row) {
$this->delete($row['DepartmentsLocation']['id']);
}
return true;
}
}
?>
The controllers are completely uninteresting.
The problem:
If I edit the name of a Location, all of the DepartmentsLocations that were linked to that Location are re-created with empty URLs. Since the models specify that unique is true, this also causes all of the newer rows to overwrite the older rows, which essentially destroys all of the URLs.
I would like to know two things:
Can I stop this? If so, how?
And, on a less technical and more whiney note: Why does this even happen? It seems bizarre to me that editing a field through Cake should cause so much trouble, when I can easily go through phpMyAdmin, edit the Location name there, and get exactly the result I would expect. Why does CakePHP touch the HABTM data when I'm just editing a field on a row? It's not even a foreign key!
From the CookBook the 1st problem is:
By default when saving a
HasAndBelongsToMany relationship, Cake
will delete all rows on the join table
before saving new ones.
I am not quite sure why Cake is trying to save the HABTM data even though you don't have a foreign key in your data, but there is an easy solution for that. Simply destroy the association for the save call:
$this->Location->unbindModel(
array('hasAndBelongsToMany' => array('Department'))
);
I'm thinking of one reason why this might be happening. When you retrieve Location, you also retrieve locations_departments data. And when you do a save($this->data) it looks for models in the array and saves them.
A way to solve this is setting the recursive attribute (of a model) to -1 or 0 (try, I'm not sure, just print out the data to see what comes out). You can set it in the model: var $recursive = -1; or in the controller method (action): $this->ModelName->recursive = -1;
More about recursive: http://book.cakephp.org/view/439/recursive
It's really similar to what harpax suggested, just if you don't need that data, tell it to Cake, so that it won't fetch it.
Trouble is that when saving your Location, you gave the save method an array containing all the DepartmentsLocations too. Thus CakePHP destroys everything and try to recreate it.
This is a common mistake with cake since it will often pull far too many results for you.
Be sure to pass only the data that needs to be saved, or better to fetch only the datas you need.

Resources