CakePHP baking fixtures doesn't care about unique fields - cakephp

An example:
I have a User model with a field 'username'
In the $validate array, I have set 'isunique' rule for 'username'. It works, no problem.
But every time I generate fixture, the auto generated value for this field is not unique.
Same problem for other models.
Any idea how to get bake to produce unique values for fileds with 'isunique' rule?
Thank you.

Why do you even think cake/fixtures would so such a thing?
It doesnt!
Your validation rules have absolutely nothing to do with your indexes.
Validation get triggered when using validates() or save().
But your database does not have to have those "unique" indexes for it to work.
If you really want them in your fixtures, too, you need to define them there manually (see the primary key index on how to do that).

Related

How to work with temporary tables defined with prepared statements in cakePHP 3.x

I'm working with cakePHP 3.7
I'd like to create a temporary table from a controller, and then use it (with some conditions and joins) to search some data to be displayed.
The table structure is for the moment statically defined, i.e. the fields it has are fixed, so I'm able to define an entity or a set of fields.
The content, though, varies with the user input. This means I want to define the table with a prepared SQL statement, whose variables I will bind to user input.
I know how to handle prepared statements.
But I've not understood yet precisely what's the correct way to proceed, to let cakePHP create my temporary table and load a model for it.
I've found a useful answer by #ndm at CakePHP 3: Best Practice for Temporary SQL Tables
and, in the tries I've made, I've specified the setTemporary(true) for the table.
Yet I keep getting "table doesn't exist" exceptions, so I suppose I'm not structuring the project classes and code correctly.
I can't create the table, as #ndm suggests, by using queries got with
$schema->createSql($connection);
because the sql is dependent to the user input.
Other found stackoverflow answers are about older versions of cakePHP (2.x) which are different from 3.x
Could someone please give me some more detailed hints about which is the way to create and use temporary tables, created with prepared statements, from within my cakePHP project?
Solved this way:
I've created a table in the database corresponding to my desired temporary table
I've run the cake bake model command to let cakePHP generate the entity and the table class
I've dropped the table from the DB
in the controller:
4.a I've prepared and executed the statement to create the temporary table
4.b I've loaded the model and used it
The issue I had was (what a shame!) a typographical error, because at a certain moment in a join query I used the name of the model instead of the name of the table in the conditions array.
I.e. I was asking wrongly for:
->join([
'table' => 'tempLogs',
'type' => 'INNER',
'conditions' => 'tempLogs.Job = Istanze.Job',
])
instead of the correct:
->join([
'table' => 'temp_logs',
'type' => 'INNER',
'conditions' => 'temp_logs.Job = Istanze.Job',
])
temp_logs is the temporary table name, TempLogs is the name of the table class

One Way One-To-One Association in CakePHP

I have an idea of how to do this but it doesn't seem like proper convention. I have a Submission model and a Revision model each with their similarly named tables. Each Submission can have one or more Revisions associated to it in a $hasMany relationship. The Revision model hence has a $belongsTo relationship linking back to the Submission.
In addition to having this relationship, the Submission model needs to have another association (called activeRevision) to a particular Revision in a $hasOne style of relationship. However, the $hasOne type requires the foreign key to be in the Revision table. I want it to be in the Submission table, so I don't need to query all of the Submission's Revisions to find the active one. I realized just specifying a $belongsTo relationship in the Submission would do what I want, but this feels wrong to me as now the two models "belong to eachother".
Is there a better way to go about this?
I wouldn't worry too much because of the 'naming' of the relation. By having the foreign key of the Revision inside the Submission table, CakePHP is, in fact, right that you've created a 'belongsTo' relation.
Although not strictly the 'right' (?) relation, in this situation, this looks like it's an easy way to achieve what you want. Just be sure to add an additional condition to your relation to prevent that a revision of another submission can be set as the current revision, i.e.;
public $belongsTo = array(
'Revision' => array(
'conditions' => array(
'Revision.submission_id = Submission.id',
)
)
);
However, make sure to add a proper comment in your code to prevent confusion if you're (or somebody else is) looking at your code in a later stage. (e.g. "note: using belongsTo relation, because its easier to maintain)
If you really want to convert it to a hasOne relation, you'll have to add an additional column to the 'Revisions' table, for example 'is_curreny_revision'. However, you will also need to be sure that only one revision of a submission can be set to be the current revision.
If you're using PostgreSQL, this can be achieved using a 'partial unique' index (see this question on StackOverflow; PostgreSQL: Conditional unique constraint). MySQL does not support partial indexes, so you're out of luck there

Saving corresponding data in a hasOne relation

As I read in other postings, the id of the table, which has a relation to the frist model has to be set by an hidden field in the form.
echo $form->input('Gallery.id', array('type'=>'hidden', 'value'=>$showcase['Gallery']['id']));
(see question at Update hasone relation behaves strangely (cakephp))
But isn't that risky, because anyone could edit this hidden field value and another dataset would be updated.
What is the best option to avoid such security issues when trying to update a whole dataset with 2 models associated together with a hasOne / belongsTo relation?
Thx
Best
Stefan
1st option is to have multiple queries and checks on save
2nd option is http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#form-tampering-prevention
So whatever method works best in your particular case...
You can switch to using UUIDs. Just need to change your primary key and foreign key to char(36) and cake will do the rest.

Deleting association from HABTM table

I have a Users and a Reports table, connected with HABTM relationship.
I can save a report that creates a correct record in reports_users table, I can view the relationship table by using $this->User->ReportsUser->.., and so on.
Now I want to delete a specific row in reports_users table, but I can't seem to do it.
I have tried the following:
$this->User->ReportsUser->deleteAll(array(
'ReportsUser.report_id' => $this->data['Report']['report_id'],
'ReportsUser.user_id' => $this->data['Report']['user_id']
));
..but it deletes all the rows with the given user_id, with this query:
What am I doing wrong here. Is it a bad data in the deleteAll call?
I don't want to delete any users or reports, only the relationship between them.
I can confirm that the table names are correct, and that the variables exist and are set.
It seems no error with your code. Either your $this->data['ReportUser']['report_id'] is having some problem. The best way is to first try to print your $this->data. And check whether it exists?
For the safety reasons, use the second argument $cascade = false and also unbind all the ReportUser model Associationship using $this->ReportUser->unbindModel() method.
The other reason seems to be deleting data through
$this->User->ReportUser. Try to use $this->ReportUser->deleteAll('your conditions', false); directly.
Please ask if it not worked for you.

cakePHP HABTM, am I getting it all wrong?

I understood that every new row, causes the deletion of the rows that were there before?
What is the idea behind it? I don't believe that it is ..
So, what am i getting wrong?
Edit A
I have a form that adds a store to the Stores table. the store have a column named owner_id which is associated to the Users table through a belongsTo relationship.
There is also a table named stores_users that supposed to store the mangers for each store, using the HABTM relationship.
For this table there is a form with an email field, that connects the user to the store by saving the record directly to the stores_users table.
So, there is no full HABTM save anywhere, if I understand the term correctly.
So, my questions are:
Should I expect problems using it this way?
Can you advice me about how to it, if my method is not the proper way?
How can I use the stored data, using $this->User->find(...) to get all the stores that the user can manage?
yes, thats the default behavior of HABTM in cakephp
although this is not on "every row", but "every HABTM save".
this is working IF you always provide all HABTM values.
and with baked views according to the specifications for such HABTM this is all working out of the box.
if you change the default behavior (old ones get not deleted) you will need to make sure that there are no duplicates. there are behaviors out there, I think, which try to accomplish that.
but I would recommend for you to build your forms the way that the default behavior of cake can do its job.
Example:
IS: 1,3,6 (in DB for this key)
NEW: 2,3,6 (coming from form)
(cake deletes 1,3,6 and adds 2,3,6)
=> overall result (forgetting about different primary keys): "1" deleted, "2" added
so it might not be the most resource sparing way but its sure the easiest and fastest.

Resources