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

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();

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.

How can I add a group by to a hasMany relationship in laravel 5.3?

I have an elquent model named Conversation.
In that model I define a hasMany relationship on an eloquent model CallParticipant like so:
public function participants(){
return $this->hasMany('App\Models\Purecloud\Analytics\CallParticipant', 'conversationId', 'conversationId');
}
Now, CallParticipants can be system processes, customers, or agents. I need a list of all the CallParticipants that are considered "agents" so I defined another relation like this:
public function agents(){
return $this->hasMany('App\Models\Purecloud\Analytics\CallParticipant', 'conversationId', 'conversationId')
->whereIn('partPurpose', ['agent','user']);
}
Now, an "agent" can be a "participant" multiple times on a "conversation" that is to say there can be multiple rows for the same agent just with a different participantId, like this:
+----------------+---------------+--------------+-------------+
| conversationId | participantId | partUserName | partPurpose |
+----------------+---------------+--------------+-------------+
| 1 | 100 | Alex | agent |
| 1 | 101 | Mary | agent |
| 1 | 102 | Alex | agent | <-- I want to exlcude this
+----------------+---------------+--------------+-------------+
I need to remove these sortof-duplicates so that the relationship only returns one row for each partUserName (one row for Mary, and one row for Alex).
I tried to do this by adding a groupBy like this:
public function agents(){
return $this->hasMany('App\Models\Purecloud\Analytics\CallParticipant', 'conversationId', 'conversationId')
->whereIn('partPurpose', ['agent','user'])
->groupBy('partUserName');
}
But this produces the error:
SQLSTATE[42000]: Syntax error or access violation: 1055 'analytics.callParticipants.participantId' isn't in GROUP BY
I also tried doing it in the with statement like below, but I get the same error:
$conversations = Conversation::with(
[
'agents' => function($query){
$query->groupBy('partUserName');
}
])
->get();
Is there any way I can limit the relationship to only rows with unique partUserName
I think that the only way to do this is by "hacking" the relation. Could you try:
public function agents(){
return $this->hasOne('App\Models\Purecloud\Analytics\CallParticipant', 'conversationId', 'conversationId')
->whereIn('partPurpose', ['agent','user'])
->latest();
}

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

Arrays in Eloquent ORM (Laravel 5, 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.