Need to make full names in cakePHP - cakephp

If I have a person model with first_name and last_name, how do I create and display a full_name? I would like to display it at the top of my Edit and View views (i.e. "Edit Frank Luke") and other places. Simply dropping echoes to first_name and last_name isn't DRY.
I'm sorry if this is a very simple question, but nothing has yet worked.
Thank you,
Frank Luke
Edit for clarity: Okay, I have a function on the person model.
function full_name() {
return $this->Person->first_name . ' ' . $this->Person->last_name;
}
In the view, I call
echo $person['Person']['full_name']
This gives me a notice that I have an undefined index. What is the proper way to call the function from the view? Do I have to do it in the controller or elsewhere?

If what you are wanting is just to display a full name, and never need to do any database actions (comparisons, lookups), I think you should just concatenate your fields in the view.
This would be more aligned with the MVC design pattern. In your example you just want to view information in your database in a different way.
Since the action of concatenating is simple you probably don't save much code by placing it in a separate function. I think its easiest to do just in the view file.
If you want to do more fancy things ( ie Change the caps, return a link to the user ) I would recommend creating an element which you call with the Users data.

The arrays set by the save() method only return fields in the datbase, they do not call model functions. To properly use the function above (located in your model), you will need to add the following:
to the controller, in the $action method:
$this->set( 'fullname', $this->Person->full_name();
// must have $this-Person->id set, or redefine the method to include $person_id
in the view,
echo $fullname;
Basically, you need to use the controller to gather the data from the model, and assign it to the controller. It's the same process as you have before, where you assign the returned data from the find() call to the variable in the view, except youre getting the data from a different source.

There are multiple ways of doing this. One way is to use the afterFind-function in a model-class.
See: http://book.cakephp.org/view/681/afterFind.
BUT, this function does not handle nested data very well, instead, it doesn't handles it al all!
Therefore I use the afterfind-function in the app_model that walks through the resultset
function afterFind($results, $primary=false){
$name = isset($this->alias) ? $this->alias : $this->name;
// see if the model wants to attach attributes
if (method_exists($this, '_attachAttributes')){
// check if array is not multidimensional by checking the key 'id'
if (isset($results['id'])) {
$results = $this->_attachAttributes($results);
} else {
// we want each row to have an array of required attributes
for ($i = 0; $i < sizeof($results); $i++) {
// check if this is a model, or if it is an array of models
if (isset($results[$i][$name]) ){
// this is the model we want, see if it's a single or array
if (isset($results[$i][$name][0]) ){
// run on every model
for ($j = 0; $j < sizeof($results[$i][$name]); $j++) {
$results[$i][$name][$j] = $this->_attachAttributes($results[$i][$name][$j]);
}
} else {
$results[$i][$name] = $this->_attachAttributes($results[$i][$name]);
}
} else {
if (isset($results[$i]['id'])) {
$results[$i] = $this->_attachAttributes($results[$i]);
}
}
}
}
}
return $results;
}
And then I add a _attachAttributes-function in the model-class, for e.g. in your Person.php
function _attachAttributes($data) {
if (isset($data['first_name']) && isset($data['last_name'])) {
$data['full_name'] = sprintf("%s %s %s", $data['first_name'], $data['last_name']);
}
return $data;
}
This method can handle nested modelData, for e.g. Person hasMany Posts then this method can also attachAttributes inside the Post-model.
This method also keeps in mind that the linked models with other names than the className are fixed, because of the use of the alias and not only the name (which is the className).

You must use afterFind callback for it.

You would probably need to take the two fields that are returned from your database and concatenate them into one string variable that can then be displayed.

http://old.nabble.com/Problems-with-CONCAT-function-td22640199.html
http://teknoid.wordpress.com/2008/09/29/dealing-with-calculated-fields-in-cakephps-find/
Read the first one to find out how to use the 'fields' key i.e. find( 'all', array( 'fields' => array( )) to pass a CONCAT to the CakePHP query builder.
The second link shows you how to merge the numeric indexes that get returned when you use custom fields back into the appropriate location in the returned results.
This should of course be placed in a model function and called from there.

Related

Difference in accessing variables in views

I've two controllers one is "Upload" which deals with images uploads and other is "Page" whid deals with the creation of pages of CMS now if in my "Upload" controller I load both the models i.e 'image_m' which deals with image upload and "page_m" which deals with the pages creation I've highlighted the relevant code my problem is if I access the variables in the view
$this->data['images'] = $this->image_m->get(); sent by this I can access in foreach loop as "$images->image_title, $images->image_path" etc
But the variable sent by this line ***$this->data['get_with_images'] = $this->page_m->get_no_parents();*** as $get_with_images->page_name, $get_with_images->page_id etc produces given error
A PHP Error was encountered
Severity: Notice
Message: Trying to get property of non-object
Filename: upload/index.php
Line Number: 20
what is the difference between these two access levels one for $image & other for $get_with_images because I can only access its values as $get_with_images
class Upload extends Admin_Controller {
public function __construct() {
parent::__construct();
***$this->load->model('image_m');
$this->load->model('page_m');***
}
public function index($id = NULL) {
//var_dump($this->data['images'] = $this->image_m->get_with_images());
//$this->data['images'] = $this->image_m->get_with_images();
***$this->data['images'] = $this->image_m->get();***
$this->data['subview'] = 'admin/upload/index';
if ($id) {
$this->data['image'] = $this->image_m->get($id);
count($this->data['image']) || $this->data['errors'][] = 'Page Could not be found';
}
$id == NULL || $this->data['image'] = $this->image_m->get($id);
/*this calls the page_m model function to load all the pages from pages table*/
***$this->data['get_with_images'] = $this->page_m->get_no_parents();***
You are not posting all your code so its hard to tell but is it because you used $this-> in the controller, but you haven't done the same thing in the view?
In this case i would recommend not using $this-> because its not necessary. Also its much better to check for errors etc when you call the model so do something like
if ( ! $data['images'] = $this->image_m->get($id) ) {
// Failure -- show an appropriate view for not getting any images
// am showing $data in case you have other values that are getting passed
$this->load->view( 'sadview', $data ); }
else {
// Success -- show a view to display images
$this->load->view( 'awesomeview', $data ); }
so we are saying if nothing came back - the ! is a negative - then show the failure view. Else $data['images'] came back, and it will be passed to the view. note i have not had to use $this-> for anything and it won't be needed in the view.
Would also suggest using separate methods - have one method to show all images and a separate method like returnimage($id) to show an image based on a specific validated $id.
====== Edit
You can access as many models as you want and pass that data to the View. You have a different issue - the problem is that you are waiting until the View to find out - and then it makes it more difficult to figure out what is wrong.
Look at this page and make sure you understand the differences between query results
http://ellislab.com/codeigniter/user-guide/database/results.html
When you have problems like this the first thing to do is make a simple view, and echo out directly from the model method that is giving you problems. Its probably something very simple but you are having to look through so much code that its difficult to discover.
The next thing is that for every method you write, you need to ask yourself 'what if it doesn't return anything?' and then deal with those conditions as part of your code. Always validate any input coming in to your methods (even links) and always have fallbacks for any method connecting to a database.
On your view do a var_dump($get_with_images) The error being given is that you are trying to use/access $get_with_images as an object but it is not an object.
or better yet on your controller do a
echo '<pre>';
var_dump($this->page_m->get_no_parents());
exit();
maybe your model is not returning anything or is returning something but the data is not an object , maybe an array of object that you still need to loop through in some cases.

Is it safe to do query with Model while in Behavior's BeforeSave callback?

I don't see this documented anywhere, so I ask you, my dear Cake-eaters.
Inside a CakePHP's Behavior::BeforeSave(&$Model) method, I read and write changes to $Model->data array. Before I am finished, I need to read some other records from the database. I am worried that, if I use $Model->find(), it will overwrite the current data within the model, which is about to be saved.
Viewing the source code, the Model::find() function clearly resets the Model::$id variable. This is the same variable I later use to check if a field is being updated.
Here's an example:
<?php
class UniqueBehavior extends ModelBehavior {
function beforeSave(&$Model){
$value = $Model->data[$Model->alias]['unique_field'];
$query = array('conditions' => array('unique_field' => $value));
if ($Model->find('first', $query){
// Does $Model::find() reset the internal $Model->data array?
$Model->data[$Model->alias]['unique_field'] = "..."
//... some other code here
}
//ALSO...
if ($Model->exists()) // Returns true if a record with the currently set ID exists.
$slug = $Model->field('slug');
// this should fetch the slug of the currently updated Model::id from the database
// if I do find()'s, can I trust that the record I'm getting is the right one?
}
}
?>
you can always store the current id in $tmp and assign this stored id back to the model after you are finished
$tmp = $Model->id;
// ...
$Model->id = $tmp;
This way you don't run into problems using the Model-id.
If it is save or not depends on how you work in your model.
I - for example - never rely on this id. I always assign the id to the model manually prior to any update or delete call etc. But this is not necessary, of course. You have to be more careful then, though.

Using existing field name as different name

i have existing website.
and i write the new back-end (in cakephp) without changing front-end programm
the discomfort that
db table has field names as
id
news_date
news_title
news_content
is it possiable to do something in cakephp model file (reindentify the field names)
so i can use model in controller as
News.date
News.title
News.content
What you need to do is setup some very basic virtual fields in your news model. Something like this should suit your needs.
public $virtualFields = array(
'title' => 'news_title',
'date' => 'news_date',
'content' => 'news_content'
);
Also do yourself a favour by checking out the other model attributes that could help you out, you'll want to set displayType as new_title I'd imagine.
Is said by Dunhamzz, virtualFields are a good solution until you want to work with these new field-names.
Since I assume your frontend needs to use the old names from the database I would go with the afterFind-callback in your model.
Let's say you've got the model news.php:
# /app/model/news.php
function afterFind($results) {
foreach ($results as $key => $val) {
if (isset($val['News']['title'])) {
$results[$key]['News']['news_title'] = $val['News']['title']);
# unset($results[$key]['News']['title']); //use this if you don't want the "new" fields in your array
}
if (isset($val['News']['date'])) {
$results[$key]['News']['news_date'] = $val['News']['date']);
# unset($results[$key]['News']['date']); //use this if you don't want the "new" fields in your array
}
if (isset($val['News']['content'])) {
$results[$key]['News']['news_content'] = $val['News']['content']);
# unset($results[$key]['News']['content']); //use this if you don't want the "new" fields in your array
}
}
return $results;
}
You need to rename the database-fields to your new wanted value. You then can use these within conditions like every other field.
Only difference is, that you get back an array where all your fields have been renamed to your frontend-fields.
For more information about the available callback-methods have a look here: Callback Methods

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

What is the equivalent to getLastInsertId() in Cakephp?

If I do getLastInsertId() immediately after a save(), it works, but otherwise it does not. This is demonstrated in my controller:
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->getLastInsertId(); //here it works
}
function insertformname() {
echo $this->Form->getLastInsertId(); //this doesnt echo at all
}
Please suggest a way to get the functionality I want.
CakePHP has two methods for getting the last inserted id: Model::getLastInsertID() and Model::getInsertID().
Actually these methods are identical so it really doesn't matter which method you use.
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
This methods can be found in cake/libs/model/model.php on line 2768
Just use:
$this->Model->id;
In Cake, the last insert id is automatically saved in the id property of the model. So if you just inserted a user via the User model, the last insert id could be accessed via $User->id
id - Value of the primary key ID of
the record that this model is
currently pointing to. Automatically
set after database insertions.
Read more about model properties in the CakePHP API Docs: http://api.cakephp.org/2.5/class-AppModel.html
Edit: I just realized that Model::getLastInsertID() is essentially the same thing as Model->id
After looking at your code more closely, it's hard to tell exactly what you're doing with the different functions and where they exist in the grand scheme of things. This may actually be more of a scope issue. Are you trying to access the last insert id in two different requests?
Can you explain the flow of your application and how it relates to your problem?
You'll need to do an insert (or update, I believe) in order for getLastInsertId() to return a value. Could you paste more code?
If you're calling that function from another controller function, you might also be able to use $this->Form->id to get the value that you want.
Try using this code in your model class (perhaps in AppModel):
function get_sql_insert_id() {
$db =& ConnectionManager::getDataSource($this->useDbConfig);
return $db->lastInsertId();
}
Caveat emptor: MySql's LAST_INSERT_ID() function only works on tables with an AUTO_INCREMENT field (otherwise it only returns 0). If your primary key does not have the AUTO_INCREMENT attribute, that might be the cause of your problems.
this is best way to find out last inserted id.
$this->ModelName->getInsertID();
other way is using
$this->ModelName->find('first',array('order'=>'id DESC'))
There are several methods to get last inserted primary key id while using save method
$this->loadModel('Model');
$this->Model->save($this->data);
This will return last inserted id of the model current model
$this->Model->getLastInsertId();
$this->Model-> getInsertID();
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of last loaded model
$this->id;
Try to use this code. try to set it to a variable so you can use it in other functions. :)
$variable = $this->ModelName->getLastInsertId();
in PHP native, try this.
$variable = mysqli_insert_id();
This will return last inserted id of last loaded model
$this->id;
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of the model current model
CakePHP has two methods for getting the last inserted id:
Model::getLastInsertID() and Model::getInsertID().
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
Below are the options:
echo $this->Registration->id;
echo $this->Registration->getInsertID();
echo $this->Registration->getLastInsertId();
Here, you can replace Registration with your model name.
Thanks
Use this one
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->id; //here it works
}
You can get last inseted id with many ways.Like Model name is User so best way to fetch the last inserted id is
$this->User->id; // For User Model
You can also use Model function but below code will return last inserted id of model with given model name for this example it will return User model data
$this->User->getLastInsertId();
$this->User->getInsertID();
When you use save(), the last insert ID is set to the model’s $id property. So:
if ($this->Model->save()) {
printf('Last insert ID was %s', $this->Model->id);
}
Each time a save method is called on a model, cake internally calls Model::getLastInsertId() and stores the result into model class attribute id, so after calling save() it is not necessary to call Model::getLastInsertId() or inserId(), as tha value can be directly accessed like this
$id = $this->id;// within a model
$id = $this->{$this->modelName}->id;// in a controller
After insertion of data, we can use following code to get recently added record's id:
$last_insert_id=$this->Model->id;
each time you perform an insert operation on any model, cake internally fetchesthe last insert Id and Sets to Model->id attribute.
so one can access it directly by $Model->id;,
no need to query again for lastInsertId.
I think it works with getLastInsertId() if you use InnoDB Tables in your MySQL Database. You also can use $this->Model->id
$Machinedispatch =
$this->Machinedispatch->find('first',array('order'=>array('Machinedispatch.id DESC')));
Simplest way of finding last inserted row. For me getLastInsertId() this not works.
Actually you are using the getLastInsertId or getInsertId in a wrong manner.
getLastInsertId() is meant to work only after save() method.
It will even not work after a manual insert, as cake engine is storing the mysql_insert_id under $this->_insertID inside the save method which can be retrieved via the getLastInsertId or getInsertId.
Now in your case
$this->Model->id
OR
$this->Model->find('first',array('order'=>'id DESC'))
Will do.
This is interesting, I also stumbled upon this issue. What you asked perhaps how to get the last ID of a certain model regardless of it's state, whether it's just been inserted or not. To further understand what getInsertID does, we need to take a look at the source:
Link 1: http://api20.cakephp.org/view_source/model#line-3375
public function getInsertID() {
return $this->_insertID
}
Yup, that's the only piece of code inside that function. It means that cakephp caches any last inserted ID, instead of retrieve it from the database. That's why you get nothing if you use that function when you haven't done any record creation on the model.
I made a small function to get the last ID of a certain table, but please note that this should not be used as a replacement of getLastID() or getLastInsertID(), since it has an entirely different purpose.
Add the function lastID() to the AppModel as shown below so that it can be used system wide. It has it's limit, which can't be used on model with composite primary key.
class AppModel extends Model {
public function lastID() {
$data = $this->find('first',
array(
'order' => array($this->primaryKey . ' DESC'),
'fields' => array($this->primaryKey)
)
);
return $data[$this->name][$this->primaryKey];
}
}
Original Source : Class Model
In CakePHP you can get it by:
Model::getInsertID() //Returns the ID of the last record this model inserted.
Model::getLastInsertID() //Alias to getInsertID().
$this->Model->field('id', null, 'id DESC')

Resources