Model association trouble with cakephp - php

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.

Related

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

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);
}),
],

How to retrieve data from two tables?

I have two tables
posts
------
post_id | user_id | post_title | post_content
And
users
--------
id | user_name | user_ . .. . . . and so on
I need to fetch all posts with the user data
to show the post writer etc..
How can I achieve this using CakePHP queries?
In your UserModel you define:
var $hasMany = 'Post';
In your PostModel you define:
var $belongsTo = 'User';
Then you can get all post of some user doing:
$this->User->findAllById($id, array('recursive' => 2));
Or you can get ALL posts associated with the respective users doing:
$this->Post->find("all", array('recursive' => 2));
EDIT:
Your Posts id column is named post_id so you must define primary key in your PostModel since CakePHP conventions is that primary key should be named id:
public $primaryKey = 'post_id';
$this->Post->find('all',array('fields'=>array('User.*'),'conditions'=>array('Post.user_id=User.id')),
joins' => array(
array(
'alias' => 'User',
'table' => 'users',
'type' => 'Inner',
'conditions' => array('User.user_id' =>$id)
)
)
));

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 Associations and Data Modelling

I am developing a web app for an art gallery, and I want to check I have set up the data model correctly.
I have a people table and an artists table. Some of the people are artists and some are not.
I also have a products table and each product belongs to one artist.
Below is a simplified version of the tables:
products
********
id
title
artist_id
artists
*******
id
profile
rating
person_id
people
******
id
first_name
last_name
I need to be able to retrieve the name of the artist when performing the find() method on the Product model.
Have I set up the data model correctly and if so what is the best way to retrieve the artist's name without getting lots of unwanted data?
It's possible to use CakePHP's bindModel & unbindModel to build up relations that don't rely on Cake's automagic goodness.
Since you were interested in doing the find on the Product model, I'll set out an example that can be called from the Products controller:
// unbind Artist
$this->Product->unbindModel(array(
'belongsTo' => array('Artist')
));
// bind Artist & Person using explicit conditions
$this->Product->bindModel(array(
'hasOne' => array(
'Artist' => array(
'foreignKey' => false,
'conditions' => array('Artist.id = Product.artist_id')
),
'Person' => array(
'foreignKey' => false,
'conditions' => array('Person.id = Artist.person_id')
),
)
));
// return the person
$person = $this->Product->find('first', array(
'conditions' => array(
'Product.id' => 1 // or any other condition
),
'fields' => array(
'Person.first_name',
'Person.last_name'
)
));
What's happening here?
Firstly, we unbind the Product model's relationship with the Artist model.
Secondly, we bind the Artist and Person models by explicitly defining the relationships and disabling Cake's automatic forigenKey connections.
Lastly, we do a 'first' find on the Product model and only request the 'first_name' & 'last_name' of the Person.
Each 'Product' belongs to an 'Artist' and each 'Artist' hasAndBelongsToMany 'Product'
You will also need the following table:
artists_products
****************
id
product_id
artist_id
http://book.cakephp.org/#!/view/1044/hasAndBelongsToMany-HABTM

How to Retrieve fields from linked Models

I have the following three database tables:
Products
########
id
title
artist_id
Arists
######
id
profile
person_id
People
######
id
first_name
last_name
In my Product model how do I create a method to return the product title along with the artist's first_name?
I have set up the following model associations:
Product belongs to Artist
Artist belongs to Person
Containable is definitely the way to go for filtering related records. Make sure to add $actsAs = array('Containable') into your model or app_model.
Then you can do things like:
$this->Product->find('all', array(
'contain' => array(
'Artist' => array(
'Person' => array(
'id',
'first_name'
)
)
)
));
Assuming you already set the relationships in these models, you just need to set it recursive:
$this->Product->recursive = 2;
print_r($this->Product->find('all'));

Categories