Laravel validation rules only ids that belong to a selected related model - php

Below is a sample of database tables.
posts table:
id name
1 A
2 B
comments table:
id post_id text
1 1 aaaaaaa
2 1 AAAAAAAAAAA
3 2 bbbbbbbbb
4 2 BBBBBBBBBBBB
5 2 b5b5b5b5b
Below is my current validation rules.
[
'post_id' => 'required|exists:posts,id',
'comment_id => 'required|exists:comments,id',
]
With the above validation rules, it validates if post_id exists in the id column of the posts table. The same for comment_id.
But in my case, if you select post id = 1, it should validate if comment_id is 1 or 2 because only these two comments belong to post id = 1.
The same if you select post id = 2, it should validate if the selected comment_id belongs to post id = 2.
Otherwise, the validation should fail even the selected comment_id do exist in the id column of the comments table.
How to make such validation in Laravel 5 or 6?

Hi here is the way you can do it. I believe you are using the Request class
This snippet will work with or without Request class
[
'post_id' => 'required|exists:posts,id',
'comment_id' => [
'required',
Rule::exists('comments')->where(function($query){
$query->where('post_id', request()->post_id)
->where('id', request()->comment_id);
}),
]
for more information you can look into docs https://laravel.com/docs/5.7/validation

'comment_id' => [
'required',
Rule::exists('comments')->where(function ($query) use($post_id) {
$query->where('post_id', $post_id);
}),
],

Related

Laravel Unique keyword for particular Column

I'm using "unique" keyword for validating unique users for employee_id in controllers, in my database there is column called company_id , while adding new user they will be set us some company_id ,when i add new user for my company employee id will be unique for my company itself , if employee_id is 4 for another company and i'm adding 4 for my company it must accept , it will check only for that particular company only.
$this->validate($request,
[
'name' => 'required',
'emp_id' => 'required|unique:users', (Here how can i check for particular company)
'email' => 'required|unique:users',
'role' => 'required',
]);
can anyone please help me ???
You should use the array syntax here and use a "custom" unique rule:
'emp_id' => [ "required", Rule::unique('users')->where(function ($query) use ($request) {
$query->where('emp_id', $request->emp_id)->where("company_id",$request->company_id);
}) ]
Something like this anyway
If emp_id and company_id is in request
'emp_id' => 'required|unique:users,emp_id|unique:users,company_id',
Check in docs : https://laravel.com/docs/master/validation#rule-unique
I assume emp_id and company_id are present in users table and you are sending in request

CakePHP empty Fields of associations are saved instead of discard

I have a small project on CakePHP. It has a table named articles, and 5 tables of Fields like categories, tags, images, etc. The associations are mostly HasOne, and associated tables has multiple column.
When saving data on articles table everything look good, but on some associations, for example: Article -> Rating, if I did not fill up some fields of Rating tables, that are being saved as null:
+----+------------+--------------+
| id | article_id | rating_value |
+----+------------+--------------+
| 1 | 36 | 3 |
| 2 | 56 | 5454.56 |
| 3 | 57 | 4 |
| 5 | 51 | NULL |
+----+------------+--------------+
If I add some validations, then I can't save the article as it need to be validated. All I want is that if rating_value is empty, then it must not be created as null (entity rejected), and the article must be saved.
Deleting articles works as expected, all related entities are deleted.
I tried altering $data on Model.beforeMarshall but the class is private in both Tables Articles and Ratings (i think associations may be the problem).
Some code (controller add):
public function add()
{
$article = $this->Articles->newEntity();
if ($this->request->is('post')) {
$article = $this->Articles->patchEntity($article, $this->request->data, [
'associated' => [
'Ratings',
]
]);
if ($this->Articles->save($article)) {
$this->Flash->success(__('Saved.'));
return $this->redirect(['action' => 'index']);
}
}
$this->set('article', $article);
}
I deleted all validations of every associated Model because of this.
// Articles Table
$this->hasOne('Ratings', [
'className' => 'Ratings',
'dependent' => true,
]);
// Ratings Table
$this->belongsTo('Articles', [
'foreignKey' => 'article_id',
'joinType' => 'INNER'
]);
// Rating.php Entity
protected $_accessible = [
'*' => true,
'id' => false
];
// Article.php Entity
protected $_accessible = [
'*' => true,
];
If you are setting rating_value then it will try to save and validate with all validation rules.
You can remove the associated data if rating_value is empty like this
$dataToSave = $this->request->data;
if(empty($dataToSave['rating']['rating_value'])){
unset($dataToSave['rating']);
}
$article = $this->Articles->patchEntity($article, $dataToSave, [
'associated' => [
'Ratings',
]
]);
I thing every thing looks good.May be your field in table has default value as null. For example:
If 'rating_value' field in your table has default value null,
make that default full to none first.
If validation fails that don't give you save anything rather than saving null value.If that still don't work for you see:
debug($this->request->data);
And look there if data are coming correctly from your view(form).
Another important thing is that you can use different validation set for association. (see here)

How should I link these models to query multi tables via CakePHP associations?

I am using cakephp 2.3.2 and I need to do a query on multi tables.
I have this database:
--------------------------------------------------------------
| Users | Agents | Companies | Ads |
--------------------------------------------------------------
| id | id | id | id |
| username | name | company | title |
| password | lastname | sector | message |
| | user_id | user_id | user_id |
--------------------------------------------------------------
These are the associations (Models):
User
hasOne Agent
hasOne Company
hasMany Ads
Agent
belongsTo User
Company
belongsTo User
Ad
belongsTo User
(NOTE: Please, keep in mind that when I add a new user that user could be an Agent OR a Company.)
QUESTION:
In my AdsController I have an action named view, there I read two params that I receve from Route:
$this->params['id']
$this->params['sector']
I need to do a query to check if the id is really associated to an Ad.id and If the sector is associated to Company.sector
I would like to check it with ONE find('first') instead of checking
If the ID exists
If the sector exists and it is associated to the user_id
How could I do it ?
(If the query finds Ad.id and Company.sector I need to retrieve all fields of Ad and Company)
At the moment my find('first') in AdsController/view is:
$options = array(
'fields' => array(
'Ad.*'
),
'contain' => array(
'User' => array(
'Company' => array(
'fields' => array(
'Company.*'
),
'conditions' => array(
'Company.sector' => $this->params['sector'],
),
)
)
),
'conditions' => array(
'Ad.id' => $this->params['id'],
)
)
$data = $this->Ad->find('first', $options);
debug($data);
The problem is that Company is now shown in the result (array).
Please, keep in mind that I only need to retrieve the array IF:
The ID of the AD exists
The sector of the Company exists
If one of above are not "true" I would like to get an empty array.
Obviously I have added Containable behavior in Ad model.
I've seen this, had same problem that for some reason contain, kinda malfunctions with that array() structure, maybe it works how it means to be, but I dont get it, anyways to retrive chain dependencies i use this kind of construction:
$options = array(
'contain' => array(
'User',
'User.Company' => array(
'conditions' => array(
'Company.sector' => $this->params['sector'],
),
)
),
'conditions' => array(
'Ad.id' => $this->params['id'],
)
)
But, you need to have in mind that conditions in contain are not the same as the conditions for main model, therfore even if the company sector does not exist but Ad with given id exits you will not receive an empty set. As far as I know you cannot use a condition to exclude results if there is no direct association between models. So you would still need to check if $result['User']['Company'] is an empty set or not.
One more thing your query array does not match structure you've provided with your question, there is no field sector in your Company table

CakePHP: Multiple links to same model

Lets say each book has AuthorA and AuthorB fields.
Both fields are foreign keys for authors table.
table authors with fields: id | name
table books with fields: id | name | a_author_id | b_author_id |
How should controller, model and view be set up to be able to create a book with dropdown list of "author a" and "author b" both coming from author table? How would form-input for author-a (and author-b) look like inside "Add" view for Book model?
You need to setup 2 belongsTo association in your Book model with different aliases for Author model.
public $belongsTo = array(
'AAuthor' => array(
'className' => 'Author',
'foreignKey' => 'a_author_id'
),
'BAuthor' => array(
'className' => 'Author',
'foreignKey' => 'b_author_id'
)
);
Use $this->Book->AAuthor->find('list') to get the authors list and set the array to view and specify same array using 'options' key in Form->input() options for both a_author_id and b_author_id fields.

Model association trouble with cakephp

I was having trouble with a voting system that I'm trying to make in cakePHP (found here cakephp is querying extra column and I can't figure out why) but I figured that out and now I'm having another issue.
I'm making a voting system, and the problem I'm having is that only one user can vote on a given post. For example, if user 1 votes on post 1, and then user 2 votes on post 1, user 2's vote will overwrite user 1's vote.
Here are my tables
Votes
id | user_id | vote
Posts
id | title | body | created | modified | user_id | vote_total
I'm having trouble setting up the associations
Users can vote on many posts
A post can have many votes, but only 1 per user
This is in my Users model
public $hasMany = array(
'Posts' => array( 'className' => 'Post'),
'Votes' => array('className' => 'Vote')
);
This is in my Posts model
public $hasMany = array( //there can be multiple votes of the same id (references post table)
'Votes' => array('foreignKey' => 'id')
);
I don't have a votes controller. It's done through a vote function on PostsController.php
public $hasMany = array( //there can be multiple votes of the same id (references post table)
'Votes' => array('foreignKey' => 'id')
);
is wrong. It should be:
public $hasMany = array( //there can be multiple votes of the same id (references post table)
'Votes' => array('foreignKey' => 'post_id')
);
And so you have to add post_id in the Vote model.

Categories