Arrays in Eloquent ORM (Laravel 5, MySQL) - mysql

I have some models:
Expert
id | name | etc
Place
id | name | etc
Review
id | expert_id | place_id | rates..
Rate
id | name | caption |
I need to store rates in Review model (personal, location, internet etc) (or in another model if its not possible). Each Rate haves name and caption
But how should I add values of more than one rate in review? Maybe arrays or something else?
I have this relations
class Place extends Model {
public function reviews() { return $this->hasMany('App\Review'); }
}
class Expert extends Model {
public function reviews() { return $this->hasMany('App\Review'); }
}
I don't know how to make relation Review->Rate, because one review have more than one Rate with value. Where should I store this value? Model Rate contains rate types: only id, name and caption of each rate type.

You have to specify your relationships and relate them together. you can use One-to-One, One-to-Many and Many-to-Many relationships as documented here between Expert, Place, Review and Rate models, to define this relationship, at least four database tables are needed:
experts: id | name | ...
places: id | name | ...
rates: id | name | caption | ...
reviews id | expert_id | place_id | rate_id | ...
For example, you can define many-to-many relationship between expert and place like this:
class Expert extends Model
{
/**
* The places that belong to the user.
*/
public function places()
{
return $this->belongsToMany('App\Place', 'reviews');
}
}
Then you can use attach, detach and sync methods as documented here to insert many-to-many relationships into reviews table:
$expert = App\Expert::find(1);
$expert->places()->attach($placeId, ['rate_id' => $rateId, '...' => ...]);

Short answer would be : using one to many relationship. I wouldnt show the code on how to achieve it, until you try something and show some attempt.

Related

Laravel Relations has problem with retrieve data

I have BelnogstoMany relation in my model which I defined like this
class MailUsers extends Model
{
public function group ()
{
return $this->belongsToMany('App\Models\Group', 'user_groups','user_id','group_id');
}
}
and in the other model, I defined the relationship like this
class Group extends Model
{
public function customer ()
{
return $this->belongsToMany('App\Models\MailUsers', 'user_groups','group_id','user_id');
}
}
when I save data it saves the relation in the user_groups table without problem, and I have this data in it
select * from user_groups;
+----+---------+----------+
| id | user_id | group_id |
+----+---------+----------+
| 1 | 5 | 1 |
| 2 | 16 | 1 |
+----+---------+----------+
my problem is when I am trying to retrieve the data with relation it returns null even it has a relation in the table
$data=MailUsers::with(['group'])->get();
it keeps returning null in the group even the records has relation as I show above
if I try to print the SQL statements with toSql Function it returns this without any join
select * from mail_users;
I have no idea why that is happening , I was working with relation in laravel , and this is the first time that I have just like this problem
Try getting relationship without putting them in []
$data = MailUsers::with('group')->get();
Then, you can get the group as below
$data->pluck('group');

In a Laravel Model's relationship how do I return a relationship using GROUP BY and MAX?

I have a project, the project can have attached documents. Both projects and documents are models/tables.
Simplified example documents table:
-----------------------------------
| ID | filename | version |
-----------------------------------
| 1 | list.docx | 1 |
| 2 | list.docx | 2 |
| 3 | file.xls | 1 |
-----------------------------------
I want to have some simple version control so that if a user wants to they can 'replace' the document, with the new table row copying all of the previous entries values except for ID and version.
My issue is that I want to use a relationship to pull out all of the latest documents. I'm currently using this monstrosity in the Project model:
public function latest_documents()
{
return $this->hasMany(Document::class)
->where('version', \DB::raw('(SELECT max(d.version) from documents d where d.filename = documents.filename)'))
}
There must be a better way? I tried just using groupBy() and max() with the relationship but got errors.
EDIT: Attempted 'Laravel method' before the DB::raw solution:
public function documents()
{
return $this->hasMany(Document::class)->groupBy('filename')->max('version');
}
Error:
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
My advise is to create a MySQL view based on documents table that always contains only latest document files and simply make a relation to that view. So :
Step-1/ create the view :
create view latest_documents as
select filename,
max(version) as version,
project_id as project_id,
any_value(id) as id
from documents
group by project_id, filename;
Step-2/ create the view model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LatestDocument extends Model
{
//
}
Step-3/ add the relation to the project model :
public function latest_documents()
{
return $this->hasMany(LatestDocument::class);
}
I tested this and should work.
note: I used any_value() in step one to prevent errors according to only_full_group_by. So if you disabled this mode(I would not recommend) there is no need to use this function around the id.

Laravel Eloquent and 3 table relationship

I'm looking for some help in working out how to setup the Eloquent relationships for my application.
I have created migrations for three tables.
| users | | items | | user_items |
+-----------+ +-----------+ +------------+
| id | | id | | id |
| username | | name | | user_id |
| item_id |
| qty |
I have setup an unique index on the user_items table, limiting 1 user id to 1 item id, but with a qty column. I want to setup Eloquent so that I have two models, User and Item. Where I could say:
$item = $user->items()->first();
$name = $item->name;
$qty = $item->qty;
The problem is I'm trying to figure out if I need a 3rd model, UserItem or not.
What are you doing here is actually a M:M relationships, and Laravel Eloquent already have support for that out of the box. The user_item table you have is referred to as the pivot table.
Here's how to setup your relationship using Eloquent.
// User class
class User extends Eloquent {
public items() {
return $this->belongsToMany(Item::class)->withPivot('qty');
}
}
class Item extends Eloquent {
public function users() {
return $this->belongsToMany(User::class)->withPivot('qty');
}
}
For this to work, you will need three migrations:
one for the user table
one for the item table
one for the item_user table. In Eloquent, the pivot table consists of the two tables names in alphabetical order. separated with a dash.
following Eloquent conventions, if you set the FK to use _id, Eloquent will not need additional information. So, in your case, the FK in the item_user table should be user_id and item_id respectively.
There is no need for a ItemUser model. You can access the pivot in the relationship by doing:
$user = User::find(1);
$user->items[0]->pivot->qty; // retrieve the quantity

laravel - alternative to using enum since renaming columns is not supported

The Laravel documentation says
Note: Renaming columns in a table with a enum column is not currently
supported.
What would be a best practice alternative to using an ENUM. For example, I have a users table with a type ENUM column. I might need to modify the table in the future, and being unable to because of the existence of an ENUM column is too restrictive.
What i usually do is: Make a types table.
-----------------------
| id | type |
-----------------------
| 1 | admin |
-----------------------
| 2 | moderator |
-----------------------
In your users table make a field type_id. And create your relation in laravel:
class User extends Model
{
public function type()
{
return $this->hasOne('Type');
}
}
Now you can do:
$users = Users::where('type', '=', 1)->get();
Or:
$users = User::with(['type' => function ($query) {
$query->where('type', '=', 'admin');
}])->get();
And you can also inverse the relationship so you can query by type and load all the users like:
$all = Type::with('users')->where('type', '=', 'admin')->get();

Alternatives to store array with CakePHP+MySQL

I'm developing a website where users will be able to save in their profile a list (array) of items (which they can find also in the same website and have their own id).
This is the way I've used so far in similar situations:
- Create a 'text' (string) field in the users table in the DB and save the items separated by commas
- To read that field, use the explode method to get the array in CakePHP and then work with it
- To save the array to the DB, use the implode method to convert it to a string and be able to store it in the field
What I dont' like about this method is that it can get really complicated to deal with those lists (add items, remove items...) and you can't really access those items directly, there's always some pre-processing or post-processing to make.
For example, to make it easier to look at a specifc item in one user's list and find other users with the same item in their lists.
Is there any better way to deal with arrays in CakePHP+MySQL? I've read about serialize()/unserialize(), but I don't think that would make a big difference compared to the other method...
Thank you very much in advance for any ideas!
Definately use a table so as with Kristian Antonsen's suggestion, create an items table then create a hasManu relationship in you User model like this:
class User extends AppModel{
$hasMany = array(
'Item'
);
}
Or A HABTM relationship:
class User extends AppModel{
$hasAndBelongsToMany = array(
'Item'
);
}
Use the form helper to create inputs for items.
Hope this helps.
A database table is just a huge spreadsheet. But instead of storing one piece of information in each cell, you clump them all together in one cell. You would never do that in spreadsheet.
You should create an item table like this:
+----+--------+--------+
| ID | UserID | ItemID |
+----+--------+--------+
| 1 | 2 | 3 |
| 2 | 2 | 1 |
| 3 | 3 | 3 |
+----+--------+--------+
And possibly another table:
+----+-------------+
| ID | ItemName |
+----+-------------+
| 1 | Mathematics |
| 2 | Jogging |
| 3 | Movies |
+----+-------------+
That'll let you know that User 2 likes Movies and Mathematics, and User 3 likes Movies.