Testing BelongsToMany relationship with pivot table - laravel

I'm trying to figure out how to create all the data based on this relationship testing in Laravel.
Company Model
class Company
{
public function stores()
{
return $this->hasMany(Store::class, 'company_id');
}
public function employers()
{
return $this->belongsToMany(User::class, 'employers',
'company_id', 'user_id');
}
}
Store Model
class Store
{
public function company()
{
return $this->belongsTo(Company::class, 'company_id');
}
public function employers()
{
return $this->belongsToMany(User::class, 'employers',
'store_id', 'user_id');
}
}
User Model
class User
{
public function company()
{
return $this->belongsToMany(Company::class, 'employers',
'user_id', 'company_id');
}
public function store()
{
return $this->belongsToMany(Store::class, 'employers',
'user_id', 'store_id');
}
}
$company = Company::factory()->hasStores(
Store::factory()->hasEmployers(User::factory())
)->create();
dd($company) // App\Models\Company {#2470... Ok!
$store = $company->store()->first();
dd($store) // App\Models\Store {#2479... Ok!
$user = $store->employers()->first();
dd($user) // null (T-T)
Background: this is an application that allows a proprietor to own several companies. For that reason, I got many relationships, and even so, employees sometimes can only belong to a single company or store.

Try:
$store = $company->store->first();
dump($store);
$user = $store->employers->first();
dump($user);

Try something like this with DB Facade
private $employ;
public function setUp(): void
{
$this->employ = Employ::factory()->create([
'id' => 14,
'name' => 'Name Employ'
]);
}
public function test_pivote_table()
{
$user = User::factory()->create([
'name' => 'User test'
);
//here :)
DB::table('name_pivote_table')->insert([
'user_id' => $user->id,
'employ_id' => $this->employ->id
]);
}
Credits to Fguzman :)

Related

HasManyThrough Through Several Related Tables

I want to list a sum of related table with scenario like this:
Provinces --> Regencies --> Districts --> Villages --> Users.
I want to recap all regency, districts, villages and users on one time request through Province model.
I have created this relationship:
Province Model
public function regencies()
{
return $this->hasMany(Regency::class);
}
public function districts()
{
return $this->hasManyThrough(
District::class,
Regency::class,
'province_id',
'regency_id',
'id',
'id'
);
}
public function villages()
{
return $this->hasManyThrough(
Village::class,
District::class,
Regency::class,
'province_id',
'regency_id',
'district_id',
'id',
'id',
'id'
);
}
public function users()
{
return $this->hasManyThrough(
User::class,
Village::class,
District::class,
Regency::class,
'province_id',
'regency_id',
'district_id',
'village_id',
'id',
'id',
'id'
);
}
Regency Model
public function districts()
{
return $this->hasMany(District::class);
}
District Model
public function villages()
{
return $this->hasMany(Village::class);
}
Village Model
public function users()
{
return $this->hasMany(User::class);
}
User Model
public function village()
{
return $this->belongsTo(Village::class,'village_id');
}
This is my Controller:
public function province(){
$data = Province::whereHas('regencies',function($one){
$one->whereHas('districts',function($two){
$two->whereHas('villages', function($three){
$three->whereHas('users', function($four){
});
});
});
})->get();
return new GraphProvinceCollection(true, 'List of Data',$data);
}
This is my GraphProvinceCollection:
public $success, $message;
public function __construct($success, $message, $data)
{
parent::__construct($data);
$this->success = $success;
$this->message = $message;
}
public function toArray($request)
{
return [
'success' => $this->success,
'message' => $this->message,
'data' => $this->collection->transform(function($val){
return new GraphProvinceResource($val);
})
];
}
and This is my GraphProvinceResource:
public function toArray($request)
{
return [
'province' => $this->name,
'regencies' => $this->regencies->count(),
'districts' => $this->districts->count(),
'villages' => $this->villages->count(),
'users' => $this->users->count(),
];
}
This is my data:
I have execute the Eloquent, the province, regency, and district return right, but the village and user return false.
How to solve this on Eloquent?
Thank you.

Failed to insert multiple tags on Laravel

I want to insert a Post record with multiple tags so here's my code in Post#store:
$post = Post::create(array(
'title' => $request->title,
'body' => $request->body,
'user_id' => Auth::id(),
));
if($post && $request->tags)
{
$tagNames = explode(',', $request->tags);
$tagIds = [];
foreach($tagNames as $tagName)
{
$tag = Tag::firstOrCreate(['name'=>$tagName]);
if($tag)
{
$tagIds[] = $tag->id;
}
}
$post->tags()->attach($tagIds);
}
but it give me an errors "Call to a member function attach() on null". when i'm checked in mysql the tags is already in there but i can't find any entry on my post_tag tables. here's my post model:
class Post extends Model
{
protected $fillable = ['user_id','title','slug','body','tags','category_id','featured'];
public function category()
{
return $this->belongsTo('App\Category');
}
public function tags()
{
$this->hasMany('App\Tag');
}
}
You need to return the call the hasMany in your Post model.
public function tags()
{
return $this->hasMany('App\Tag');
}
Update
You should use belongsToMany not hasMany.

BelongsTo relationship returns null when using relation name "user"

When creating a simple one-to-one relationship in Laravel 5.5, $person->user is returning a null value whenever I use the method/relation name user. If I change the name to foo, User, or login the code seems to work fine. This is the second project I've had this same issue on. Can anyone see what I'm doing wrong?
In Person model:
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function foo() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function getUser() {
if ($this->user_id) {
return User::find($this->user_id);
} else {
return null;
}
}
In PersonTest:
$user = factory(User::class)->create();
$person = factory(Person::class)->create(['user_id' => $user->id]);
// This works
$this->assertTrue( $person->getUser()->is($user) );
// This works
$this->assertTrue( !is_null($person->foo) );
if ( $person->foo ) {
$this->assertTrue( $person->foo->is($user) );
}
// This fails
$this->assertTrue( !is_null($person->user) );
if ( $person->user ) {
$this->assertTrue( $person->user->is($user) );
}
By request, here is all of the code relating to Person,
Entire App\Models\Person.php:
use App\Models\User;
use App\Models\Asset;
use App\Traits\HasGuid;
use App\Traits\HasNotes;
use App\Traits\HasModifiedBy;
use App\Traits\HasAttachments;
use App\Traits\HasRelationships;
use App\Transformers\PersonTransformer;
use App\Models\Abstracts\HasTypeModelAbstract;
use App\Models\Interfaces\HasTypeModelInterface;
class Person extends HasTypeModelAbstract implements HasTypeModelInterface {
use HasModifiedBy,
HasNotes,
HasAttachments,
HasRelationships;
protected $fillable = [
'person_type_id',
'email',
'fname',
'lname',
'user_id',
'modified_by_user_id',
'audited_at',
'custom_attributes'
];
protected $casts = [
'custom_attributes' => 'json',
'user_id' => 'integer',
'modified_by_user_id' => 'integer',
'person_type_id' => 'integer'
];
protected $dates = [
'audited_at'
];
public static $transformer = PersonTransformer::class;
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function type() {
return $this->belongsTo(PersonType::class, 'person_type_id');
}
public function assets() {
return $this->hasMany(Asset::class, 'person_id');
}
Traits:
trait HasNotes {
protected static function bootHasNotes() {
static::deleting(function ($instance) {
$instance->notes->each(function ($note) {
$note->delete();
});
});
}
public function notes() {
return $this->morphMany(Note::class, 'notable');
}
}
trait HasModifiedBy {
protected static function bootHasModifiedBy() {
static::saving(function ($instance) {
$instance->modified_by_user_id = Auth::id();
});
}
public function modifiedBy() {
return $this->belongsTo(User::class, 'modified_by_user_id');
}
}
trait HasAttachments {
protected static function bootHasAttachments() {
static::deleting(function ($instance) {
$instance->attachments->each(function ($attachment) {
$attachment->delete();
});
});
}
public function attachments() {
return $this->morphMany(Attachment::class, 'attachable');
}
}
trait HasRelationships {
protected static function bootHasRelationships()
{
static::deleting(function ($instance) {
Relation::forObject( $instance )->delete();
});
}
public function related() { ...[long polymorphic relationship here]... }
/App/Models/Abstracts/HasTypeModelAbstract
use Illuminate\Database\Eloquent\Model;
// This thing just appends some custom attributes dynamically in the JSON and array forms. And no, 'user' is not a custom attribute key.
abstract class HasTypeModelAbstract extends Model {
public function newFromBuilder($attributes = array(), $connection = NULL) {
$instance = parent::newFromBuilder($attributes);
$instance->appendCustomAttributes();
return $instance;
}
protected function appendCustomAttributes() {
$this->append( $this->getCustomAttributesFromType() );
}
public function getCustomAttributesFromType() {
if ($this->type) {
return $this->type->custom_attributes ?
array_keys((array) $this->type->custom_attributes) : [];
} else {
return [];
}
}
protected function setCustomAttributesFromType($attributes = array()) {
if ($this->type) {
$custom_attribute_keys = $this->getCustomAttributesFromType();
$custom_attributes = (array) $this->custom_attributes ?: [];
foreach ($custom_attribute_keys as $key) {
$attributes[$key] = array_get($custom_attributes, $key);
}
}
return $attributes;
}
protected function addMutatedAttributesToArray(array $attributes, array $mutatedAttributes) {
$this->appendCustomAttributes($this, $attributes);
$attributes = $this->setCustomAttributesFromType($attributes);
return parent::addMutatedAttributesToArray($attributes, $mutatedAttributes);
}
protected function mutateAttribute($key, $value)
{
$keys = $this->getCustomAttributesFromType();
if ( in_array($key, $keys) ) {
return $this->getCustomAttributeValue( $key, $value );
}
return parent::mutateAttribute($key, $value);
}
protected function getCustomAttributeValue($key, $value) {
$custom_attributes = (array) $this->custom_attributes ?: [];
return array_get($custom_attributes, $key, $value);
}
I have to be honest - quickly looking at the code I don't see anything wrong but it doesn't mean everything is for sure ok.
If I were you, I would try to limit Person model just to:
class Person extends \Illuminate\Database\Eloquent\Model {
protected $fillable = [
'person_type_id',
'email',
'fname',
'lname',
'user_id',
'modified_by_user_id',
'audited_at',
'custom_attributes'
];
protected $casts = [
'custom_attributes' => 'json',
'user_id' => 'integer',
'modified_by_user_id' => 'integer',
'person_type_id' => 'integer'
];
protected $dates = [
'audited_at'
];
public static $transformer = PersonTransformer::class;
public function user() {
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function type() {
return $this->belongsTo(PersonType::class, 'person_type_id');
}
public function assets() {
return $this->hasMany(Asset::class, 'person_id');
}
}
and now I would verify if everything is fine. If it's fine, now you could investigate this further, add one trait and verify, add second trait and verify, finally extend from same class.
There must be bug somewhere but looking at this code it's hard do find anything
user is reserved name in eloquent.
try User instead of user
public function User() {
return $this->belongsTo(User::class, 'user_id', 'id');
}

Add default value to pivot table (users_roles) when creating a new user

Been searching the internet to get an answer to my problem but can't find it :-(
I created a Roles/Permissions ability in my Laravel project by taking a videocourse. It uses pivot tables.
My database contains the following standard Laravel tables after php artisan make:auth (and migrate):
users
password_resets
For the roles/permissions ability I created the following tables:
roles (id, name)
permissions (id, name)
roles_permissions (role_id, permission_id)
users_roles (user_id, role_id)
users_permissions (user_id, permission_id)
I also created a Trait:
<?php
namespace App\Permissions;
use App\{Role, Permission};
trait HasPermissionsTrait
{
public function givePermissionTo(...$permissions)
{
$permissions = $this->getAllPermissions(array_flatten($permissions));
if ($permissions === null) {
return $this;
}
$this->permissions()->saveMany($permissions);
return $this;
}
public function withdrawPermissionTo(...$permissions)
{
$permissions = $this->getAllPermissions(array_flatten($permissions));
$this->permissions()->detach($permissions);
return $this;
}
public function updatePermissions(...$permissions)
{
$this->permissions()->detach();
return $this->givePermissionTo($permissions);;
}
public function hasRole(...$roles)
{
foreach ($roles as $role) {
if ($this->roles->contains('name', $role)) {
return true;
}
}
return false;
}
public function hasPermissionTo($permission)
{
return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission);
}
protected function hasPermissionThroughRole($permission)
{
foreach ($permission->roles as $role) {
if ($this->roles->contains($role)) {
return true;
}
}
return false;
}
protected function hasPermission($permission)
{
return (bool) $this->permissions->where('name', $permission->name)->count();
}
protected function getAllPermissions(array $permissions)
{
return Permission::whereIn('name', $permissions)->get();
}
public function roles()
{
return $this->belongsToMany(Role::class, 'users_roles');
}
public function permissions()
{
return $this->belongsToMany(Permission::class, 'users_permissions');
}
public function giveRoleTo(...$roles)
{
$roles = $this->getAllRoles(array_flatten($roles));
if ($roles === null) {
return $this;
}
$this->roles()->saveMany($roles);
return $this;
}
public function withdrawRoleTo(...$roles)
{
$roles = $this->getAllRoles(array_flatten($roles));
$this->roles()->detach($roles);
return $this;
}
public function updateRoles(...$roles)
{
$this->roles()->detach();
return $this->giveRoleTo($roles);;
}
}
My UsersController look like this (the create method):
public function store(CreateUserRequest $request)
{
$user = User::create([
'achternaam' => request('achternaam'),
'voorletters' => request('voorletters'),
'district_id' => request('district_id'),
'gemeente_id' => request('gemeente_id'),
'minister_id' => request('minister_id'),
'periode_van' => request('periode_van'),
'periode_tot' => request('periode_tot'),
'email' => request('email'),
'password' => bcrypt(request('password')),
'active' => false
]);
return redirect('/home')->withInfo('Een account activatie mail is verstuurd.');;
}
What I would like to do is to give a newly created user a default role of user (id='10', name='user' in the users_roles table).
When I use the method roles() to create a new record for that newly created user I get an error saying that the column 'role' does not exist in the roles table. Which is true because it only has an id & name column.
Can someone tell me why? And even better give me some code example to fix this problem?
Thanks in advance.

Laravel hasManyThrough relationship with League/Fractal

I'm struggling to get my head around a Laravel hasManyThrough and League/Fractal Transformers.
I have three tables:
Countries:
-id (int)
-other fields ...
Cities:
-id (int)
-country_id (int)
-other fields ...
Users
-id (int)
-city_id (string)
-some other ...
I'm trying to access Users relation from Country via Cities table relation, which is working using following Eloquent query:
$countryUsers = Country::with('users')->where('id', $id)->get();
But when I am trying to user $fractal to transform this relation, I'm getting Segmentation fault (core dumped) error.
In Country Controller I have:
class CountryController extends ApiController
{
protected $manager;
function __construct(Manager $manager) {
$this->manager = $manager;
}
public function show(CountryTransformer $countryTransformer, $id) {
$country = Country::find($id);
return $this->respondItem($country, $countryTransformer);
}
public function respondItem($item, $transformer)
{
$this->manager->setSerializer(new CustomArraySerializer());
$resource = new Item($item, $transformer);
$data = $this->manager->createData($resource)->toArray();
return $this->respond($data);
}
In my country model I have:
public function users() {
return $this->hasManyThrough('App\Models\User', 'App\Models\City');
}
public function cities() {
return $this->hasMany('App\Model\City');
}
City Model:
public function country() {
return $this->belongsTo('App\Models\Country');
}
User Model:
public function city()
{
return $this->belongsTo('App\Models\City');
}
and Fractal country transformer:
<?php namespace App\Transformers;
use App\Models\Country;
use League\Fractal\TransformerAbstract;
class CountryTransformer extends TransformerAbstract {
protected $defaultIncludes = [
'users'
];
public function transform(Country $country)
{
return [
'id' => $country->id,
'name' => $country->name,
'code' => $country->code,
'time_zone' => $country->time_zone,
'active' => $country->active,
'status' => $country->status,
'params' => $country->params
];
}
public function includeUsers(Country $country)
{
$users = $country->users;
if ($users) {
return $this->collection($users, new UserTransformer());
}
}
}
If anyone can point me in the right direction I'd really appreciate it. Thanks.

Resources