cakephp id convention saveField issue - cakephp

I have a "production" table with field employee_id as a belongsTo relation to employees table.
The problem is my employees table uses field emp_appserial as primary key -as opposed to id field- (not every entry on employees table gets an id value, everyone gets auto increment emp_appserial)
I wonder if there is a way to use saveField using a field other than id to get to my record: (I mentioned I have records with no "id" value, only emp_appserial, which is pk)
$this->loadModel('Employees');
$this->Employees->id = $id;
$this->Employees->saveField('emp_hrnote', 'text to be saved');
I'd like to use:
$this->Employees->emp_appserial = $id;
instead of
$this->Employees->id = $id;
I that doable?
Aside from that, it may not be too late to re-design my tables, but I already have a lot of production data :-(
Thank you for any pointers.

The following should do the trick (btw, models should be singular):
class Employees extends Model {
public $primaryKey = 'emp_appserial';
}
If you don't set the $primaryKey attribute, it gets set to id: Source
Once you set that saveField() will use that field for the condition: Source
Edit: Just to make it clear, you would still use Model::$id to set the primary key value. Model::$id holds the primary key value, Model::$primaryKey holds the primary key field

Used
$this->Employee->updateAll(
array('Employee.emp_hrnote' => "$thetxt"),
array('Employee.emp_appserial' => $id)
);
As a workaround is just fine, however I wish I could solve my empty id issue... will post another issue with this on another post.

Related

How to generate gii crud Yii2 without Primary Key?

How can i generate the crud wihtout primary key because, my dabatase, this table don't have a primary key. there is FK only.
when i try to generate it will be like this
image.
Thank you for your help.
I think, it is not very good to use CRUD without PK. But, if there are no other options, you can add fake PK variable to table temporarily and after generation delete that. You should change some code to escape errors on generated files (controller and views) to remove references to that fake variable. And you should be more careful, because, you could update or delete some other record instead needed one
Update
Assuming that the DB structure is like this one and you should generate CRUD for the table 'othertable', you can:
add PK as "id" to the table
regenerate model "Othertable"
generate CRUD for "othertable"
Remove id from table
Regenerate "Othertable"
Add these lines to "Othertable":
//imitate id
public $id;
//rediclare init
public function init() {
parent::init();
$this->id= $this->sometable_id;
}
// Rediclare primary key. For this condition sometable_id
// have chosen as primary
// key. We can change it
public static function primaryKey() {
return ['sometable_id'];
}
Remove id from OthertableSearch model
Change findModel($id) method on OthertableController as:
protected function findModel($id)
{
if (($model = Othertable::find()->where(['sometable_id'=>$id])->one()) !== null) {
$model->id=$model->sometable_id;
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
Attentions
In this example I used sometable_id of the "othertable" assuming that there is only one record on the table with this sometable_id value (a.g. unique), otherwise every time you can get first record and change/delete that instead needed one. It can be changed to other unique variable(s) of the table. If you want use other variable, you should change on model and on findModel() method of the controller.

findOrFail Laravel 5 function for specific field

This is my code:
$get_all = Geo_Postal_us::findOrFail($postal);
With this query, Laravel tries to find the id field in the table.
I don't have an id field. I use the postal column as primary key.
How do you set the function to find value in postal column and not search from id column?
Thanks,
You could create the behaviour you are looking for with the following:
Geo_Postal_us::where('postal', $postal)->firstOrFail();
Laravel by default is searching for the "id" column inside the table if you are using find(). To avoid running into errors here and maybe later, you should always tell laravel that you did take another name for your primary field.
To do that, in your Geo_Postal_us just edit as the following:
class Geo_Postal_us extends Model
{
protected $primaryKey = 'postal'; //tell laravel to use 'postal' as primary key field
...
...
I ran into this issue within Voyager and it really drove me nuts :).
Hope this helps some people as they google the issue.

How to update an existing record in CakePHP?

I am using CakePHP and following its tutorial. I want to update a record but when i do its create another record not updating. according to tutorial my code is given below
$data = array('Id' => $id, 'Approved' => 12);
$this->names->save($data);
it results in
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
4 for key PRIMARY
And if I do this
$this->names->Id=$id;
It adds a new record. How should I fix this ?
$this->names->id=$id;
$this->names->set(array('Approved'=>12));
$this->names->save();
The key must be id and not Id. If in your table you can't use id (lowercase) and you have to use Id (uppercase) then you have to set it in your Model file
also you are not followeing the conventions: the model should be Name and not names (singular and CamelCase)
Unless you're intentionally not following Cake naming conventions (with a strong reason), you should stick to it. That means, models should be capitalized-singular named, and table fields should be lowercase. Also, your data array has to have the name of the model you want to save.
So:
$data = array('Name' => array('id' => $id, 'approved' => 12));
$this->Name->save($data);
To update a single field value when you have the primary key available, saveField() is also available.
Quoting from documentation:
Model::saveField(string $fieldName, string $fieldValue, $validate = false)
Used to save a single field value. Set the ID of the model
($this->ModelName->id = $id) just before calling saveField(). When
using this method, $fieldName should only contain the name of the
field, not the name of the model and field.
For example, to update the title of a blog post, the call to saveField
from a controller might look something like this:
$this->Post->saveField('title', 'A New Title for a New Day');
It also has facility for passing parameters like validate, callbacks etc using an alternate syntax:
saveField(string $fieldName, string $fieldValue, array $params = array())
References: Documentation, API

cakePHP- saveAssociated() update

I have two models, donors hasMany donations.
Upon creation of donor record, I want to update some donor fields. I tried using saveAssociated() as follows
$this->Donation->create();
$this->request->data['Donation']['donor_id'] = $id;
$this->request->data['Donor']['last_donated'] = date('Ymd H:i:s', strtotime('now'));
if($this->Donation->saveAssociated($this->request->data , array('deep' => true))){
}
Everything works except that the donor is not updated but a new donor record is created altogether.
Do I need to set the donor id manually somehow?
"Do I need to set the donor id manually somehow ?"
Yes.
More explanation:
In cake, if you want to update something, you need to pass the id, otherwise you'll create a new record. You can also "load" the model instance like
$this->Model->id = $id;
and then the save will update the row with that id. But I always find it more mentally-safe to add the id to the saved array, specially when using saveAll, saveMany and saveAssociated.
In your case, you must have the donor's id somewhere, cake is not that magical and it won't know what donor you are refering to.
Something like this
$this->request->data['Donor']['id'] = $the_id;
will do the trick.
... or you can save the donor's last_donated time with a different query, if it's giving you too much trouble.

One To Many and Duplicate entry

I use JPA->Hibernate. PlayFramework. I want to have relationship.
Category - 1:n -> Tag
Every category can have many tags, but tags do not know about it.
So, i do like this:
#Entity
public class Category ... {
#OneToMany
public List<Tag> tags = new LinkedList<Tag>();
}
I have test:
#Test
public void playWithTags() {
Tag tag1 = new Tag("tag1").save(); // managed by playframework
Category cat1 = new Category("cat1");
cat1.tags.add(tag1);
cat1.save();
// check if tag1 and cat1 were saved
assertEquals(1, Tag.count());
assertEquals(1, Category.count());
Category cat2 = new Category("cat2");
cat2.tags.add(tag1);
cat2.save();
}
The result is:
16:18:01,555 ERROR ~ Duplicate entry '1' for key 'tags_id'
16:18:01,555 ERROR ~ Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelp
....
java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.BatchUpdateException: Duplicate entry '1' for key 'tags_id'
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020)
It seems that cat2.save() try to do more then it should
If if use merge() instead of save() it works good:
cat2.merge();
BUT WHY?
I have fixed the problem. The problem was in that, that I used NOT THAT annotation. So i just changed #OneToMany to #ManyToMany and voilĂ  - No any restrictions anymore.
But if saying about the OneToMany then it seems there was a unique-restriction on database-level which prevented us to put not-unique values to tags_id. Therefore we could not put same tag to One category. I.e. it wanted One category for Many tags, but if tags were already 'used' - no way.. I tried to put unique=true/false in #JoinTable -> #JoinColumn - but it does not help. For me it's still strange, but at least current problem was fixed.
You're mixing up two concepts: Primary key and foreign key.
There can be only one PK but FK just means "there must be an element with this ID in some other table". FK doesn't constrain uniqueness.
[EDIT] Your problem is that you're mixing entities. How did you get the tag1 which is returned by save()?
This entity must be one which you get from Hibernate, not the result from new. Even if it looks insane, you must do this in save():
session.save(tag);
return session.load(tag.getId());
This way, you get an entity that is managed by Hibernate. Only when the entity is managed by Hibernate, Hibernate knows when it has to save the entity and when it has already been saved.
So when you do cat2.tags.add(tag1); in your example above, Hibernate thinks "oh, I don't know anything about this tag, it must be a new one".
And tries to save the tag again.

Resources