I have a Person class (App\Models\Person) and an Organization class (App\Models\Organization) which have a polymorphic relationship with User (App\Models\User). I am using Modules (nwidart/laravel-modules).
In my App\Providers\AppServiceProvider in the boot method I have this relationship:
Relation::morphMap(
[
'organizations' => 'App\Models\Organization',
'persons' => 'App\Models\Person',
]
);
Now, I have a module called Contracts, that module has a Person model (Modules\Contracts\Entities\Person) which extends from App\Models\Person. I also have a User model (Modules\Contracts\Entities\User) which extends from App\Models\User.
I added the following code to the ContractsServiceProvider boot method:
Relation::morphMap(
[
'persons' => 'Modules\Contracts\Entities\Person',
]
);
Now, if I go to any controller and I load a Person like this:
$person = \App\Models\Person::find( 1 );
The relationship with User doesn't exist, so I can't do $person->users()->first();
But if I load a Person like this:
$person = \Modules\Contracts\Entities\Person::find( 1 );
The relationship works like a charm.
The fun part is that all the relationship methods with users are inside the files User.php and Person.php in the app\Models directory.
In app\Models\User.php I have:
class User extends Authenticatable implements MustVerifyEmail {
public function usable()
{
return $this->morphTo();
}
}
In my app\Models\Person.php
class Person extends Model {
public function users()
{
return $this->morphMany( User::class, 'usable', 'usable_type', 'usable_id' );
}
}
Also, when I create an \App\Models\Userfrom an \App\Models\Person like this:
$person = \App\Models\Person::find( 1 );
$person->users()->create( [ ... ] );
The record in the database in the users table is like this:
+------------------------------------------------------------------------+
| id | email | usable_id | usable_type |
+------------------------------------------------------------------------+
| 1 | some#email.com | 3 | App\Models\Person |
+------------------------------------------------------------------------+
But if I create the user from a \Modules\Contracts\Entities\Person like this:
$person = \Modules\Contracts\Entities\Person::find( 1 );
$person->users()->create( [ ... ] );
The record in the database in the users table is like this:
+------------------------------------------------------------------------+
| id | email | usable_id | usable_type |
+------------------------------------------------------------------------+
| 1 | some#email.com | 3 | persons |
+------------------------------------------------------------------------+
I wonder if the ContractsServiceProvider is somehow overriding the AppServiceProvider and causing my relationship to fail. Any help would be appreciated.
Thanks
Related
UPDATE: The issue mentioned here has caused by the use of MariaDB instead of MySQL by XAMPP. I have followed the answer here to switch it to MySQL and it works like a charm.
This is regarding an e-commerce platform.
I have 2 data tables with 1 joining table for a many-to-many join. The idea is for Products to have many Special Offers running at any given time.
Tables
products
+-------+-------------------------------+
| id | name |
+-------+-------------------------------+
| 10001 | Apple iPhone 11 |
| 10002 | Samsung Galaxy S11 |
+-------+-------------------------------+
special_offers
+----+-------------------------------+
| id | name |
+----+-------------------------------+
| 1 | Awesome Offer |
| 2 | Year End Offer |
+----+-------------------------------+
product_special_offer
+------------+------------------+----------+
| product_id | special_offer_id | discount |
+------------+------------------+----------+
| 10001 | 1 | 10.0 |
| 10002 | 2 | 12.5 |
+------------+------------------+----------+
Models
Since the requirement is for a many-to-many relationship, I am using belongToMany method in my models.
Product
class Product extends Model
{
public function specialOffers()
{
return $this->belongsToMany(SpecialOffer::class)->withPivot('discount');
}
}
SpecialOffer
class SpecialOffer extends Model
{
public function products()
{
return $this->belongsToMany(Product::class)->withPivot('discount');
}
}
Controller
The following is the controller snippet.
ProductController
class ProductController extends Controller
{
public function index()
{
$product = Product::find(10001);
dd($product->specialOffers);
}
}
Results
The following is what Laravel returns.
Collection {#610 ▼
#items: []
}
The query it runs is mentioned below.
select `special_offers`.*, `product_special_offer`.`product_id` as `pivot_product_id`, `product_special_offer`.`special_offer_id` as `pivot_special_offer_id`, `product_special_offer`.`discount` as `pivot_discount` from `special_offers` inner join `product_special_offer` on `special_offers`.`id` = `product_special_offer`.`special_offer_id` where `product_special_offer`.`product_id` = 10001
This could work
class SpecialOffer extends Model
{
public function products()
{
return $this->belongsToMany(Product::class, 'product_special_offer','special_offer_id','product_id');
}
}
Make a third model to the connection table, and add the two relation. And it's will work.
class ProductSpecialOffer extends Model
{
public function products() {
return $this->belongsTo(Product::class);
}
public function specialOffers() {
return $this->belongsTo(SpecialOffer::class);
}
}
Here is my model User.php
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password', 'cell_phone', 'province_id', 'city_id', 'job'
];
protected $hidden = [
'password', 'remember_token',
];
public function city()
{
return $this->belongsTo('City');
}
}
And here is a part of my controller:
$user_info = User::find(Auth::user()->id);
dd($user_info->city);
And it throws this:
"Undefined class constant 'city'"
How can I fix the problem?
Tables structure:
// users
+----+--------+---------+----------
| id | name | city_id | ...
+----+--------+---------+----------
| 1 | Jack | 5 | ...
// city
+----+--------+
| id | name |
+----+--------+
| 1 | Tehran |
You need to pass full class name:
return $this->belongsTo('App\City');
Or:
return $this->belongsTo(City::class);
Also, you don't need to do that:
$user_info = User::find(Auth::user()->id);
Because Auth::user() already has user instance loaded, you can just get city instance with:
Auth::user()->city
Basically , you don't provide full path of your class name of city that's why you belongs To relation not working properly.
for example your code must be
return $this->belongs To('App/City');
Because your in app folder you have city class module and others.
i am now working on a messaging system with laravel. Now i want to have a list of users the current user send message to / receive from. suppose i have a message table like
id | sender_id | receiver_id | msg
1 | 1 | 2 | smadksamdksa
2 | 3 | 4 | hi
3 | 1 | 2 | www
4 | 2 | 1 | ssse
5 | 3 | 1 | hi
i find get a list of id of user i talked to, the result for the user 1 will be
id
2
3
model of message
namespace App;
use Illuminate\Database\Eloquent\Model;
class msg extends Model
{
protected $table = 'msgs';
public function user()
{
return $this->belongsTo('App\user');
}
}
the query i made
$senders = msg::select('sender_id')->where('receiver_id', '=', Auth::id())->distinct()->get();
$peopleUserTalkedTo = msg::select('receiver_id')->where('sender_id', '=', Auth::id())->distinct()->union($senders)->get();
but it doesn't work with an error
Undefined property: Illuminate\Database\Eloquent\Collection::$bindings
what's wrong with it, and can i SELECT sender id and receiver AS id, can i get the user id from it later on?
I think the problem is about the union method.
You should define your models like this:
namespace App;
use Illuminate\Database\Eloquent\Model;
class msg extends Model
{
protected $table = 'msgs';
public function sender()
{
return $this->belongsTo('App\user','sender_id');
}
public function receiver()
{
return $this->belongsTo('App\user','receiver_id');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class user extends Model
{
public function talkedTo()
{
return $this->hasMany('App\msg','sender_id');
}
public function relatedTo()
{
return $this->hasMany('App\msg','receiver_id');
}
}
Now try to fetch people you talked to like this:
Auth::user()->talkedTo()->get();
Auth::user()->relatedTo()->get();
Updated
For getting only ids of the people you talked to or related to follow the code:
Auth::user()->talkedTo->pluck('id');
Auth::user()->relatedTo->pluck('id');
didnt realy get what u want but Try this after being sure to add this to ur user model
class user extends Model
{
public function msgs()
{
return $this->hasMany('App\msg');
}
}
then
$mymsgs = Auth::user()->msgs->get(); //collection of all msgs
and then you can use a foreach loop
I need to refactor project and I have problem. Below is old, working model, where 'active' column is in "people" table. I need to move 'active' column into "people_translations" table.
Do you have any Idea to modify scopeActive method?
Thanks a lot!
Old working model:
class BaseModel extends Eloquent
{
public function scopeActive($query)
{
return $query->where($this->table . '.active', '=', 1);
}
}
class People extends BaseModel
{
protected $table = 'peoples';
protected $translationModel = 'PeopleTranslation';
}
class PeopleTranslation extends Eloquent
{
public $timestamps = false;
protected $table = 'peoples_translations';
}
Old tables structure:
Table: peoples
id | type | date | active
-------------------------
7 | .... | ... | 1
Table: peoples_translations
id | people_id | language_id | name
-----------------------------------
1 | 7 | 1 | Ann
Old query:
$peoples = \People::active()->get();
New tables structure:
Table: peoples
id | type | date
----------------
7 | .... | ...
Table: peoples_translations
id | people_id | language_id | name | active
--------------------------------------------
1 | 7 | 1 | Ann | 1
Create a relation for translations inside People Model
public function translations()
{
return $this->hasMany('PeopleTranslation', 'people_id');
}
Create active scope in People model
public function scopeActive($query)
{
return $query->whereHas('translations', function($query) {
$query->where('active', 1);
});
}
It will make subquery for this table and as a result it will get where (count of translations with active = 1) > 0.
If you have one-to-one relation - look for hasOne relation method instead of hasMany.
I try create simple model with Laravel and Eloquent.
Here my code example:
composer.json
"laravel/framework": "4.1.*"
routes.php
Route::controller('items', 'ItemsController');
Route::get('item/{item}', array('as'=>'item', 'uses'=> 'ItemsController#getView'));
php artisan route:
| | GET item/{item} | item | ItemsController#getView | | |
| | GET items | | ItemsController#getIndex | | |
controllers/ItemsController.php
<?php
class ItemsController extends BaseController {
public function getIndex()
{
$items = Item::all();
return View::make('items.index')
->with('title', 'Index show')
->with('items', $items);
}
public function getView($id)
{
return View::make('items.view')
->with('title', 'View show')
->with('items', Item::find($id));
}
}
models/Item.php
<?php
class Item extends Eloquent {
protected $table = 'items';
}
DB: I have MySQL table "items" with 6 rows, for example:
+----+-----------+---------------------+
| id | name | created_at |
+----+-----------+---------------------+
| 4 | ironman | 2012-04-03 10:02:44 |
| 5 | robot | 2012-04-13 10:02:44 |
+----+-----------+---------------------+
When I try to GET mydomain/item/2
Laravel say:
Call to undefined method Item::find()
And GET mydomain/items/
Call to undefined method Item::all()
What I'm missed?
It sometimes happens to me when I am changing model and table names "on the fly", and when I do a lot of migration rollback. Try to rename you model name, it works for me in most cases.