Laravel 5.2 relationships: Trying to get property of non-object - laravel-5

I have two models: Term and Post.
The Term model represents both categories and tags.
A post can belong only to a category and it can have many tags (I use the same db table for categories and tags).
class Term extends Model
{
protected $table = 'mydb_terms';
public $timestamps = true;
public function getRouteKeyName() {
return 'slug';
}
public function posts(){
return $this -> hasMany('Post');
}
}
class Post extends Model
{
use SoftDeletes;
protected $table = 'mydb_posts';
public $timestamps = true;
public function category(){
return $this -> belongsTo('Term','mydb_posts_terms', 'post_id', 'term_id')
-> withPivot('order') -> withTimestamps() -> where('type','category');
}
public function tags(){
return $this -> hasMany('Term') -> where('type','tag');
}
}
In the CategoryController I have:
class CategoryController extends Controller
{
public function getPostsOfCategory($id)
{
$posts = Term::find($id)->posts->get();
}
public function getPostsOfAllCategories()
{
//
}
}
When I try to retrieve the posts of category event with slug event (in the db the category and one post in it exist, and also the corresponding row in mydb_posts_terms) I obtain
Trying to get property of non-object
EDIT
I tried both $posts = Term::find($id)->posts()->get(); by obtaining Call to a member function and $posts = Term::find($id)->posts; by obtaining the same Trying to get property of non-object.
In the db I have:
Table mydb_terms:
| id | name | slug | type | created_at | updated_at
| 1 | event | event | category | 2016-07-01 18:00:00| 2016-07-01 18:00:00
Table mydb_posts:
| id | title | content | created_at | updated_at
| 1 | A title | a content | 2016-07-04 17:20:12| 2016-07-04 17:20:12
Table mydb_posts_terms:
| post_id | term_id | order | created_at | updated_at
| 1 | 1 | 0 | 2016-07-06 14:13:43| 2016-07-06 14:13:43

Related

hasOneThrough Laravel Eloquent Relationship

I have 3 tabes categories, sub_categories & products
category table
---------------------
| id | category_name |
---------------------
sub_category table
--------------------------------------------
| id | category_id(FK) | sub_category_name |
--------------------------------------------
product table
-----------------------------------------------------------------
| id | sub_category_id(FK) | product_name | product_description |
-----------------------------------------------------------------
**How do I get product category name using hasOneThrough eloquent relationship ( or using any other relationship).
I tried this in product model **
public function category(){
return $this->hasOneThrough(
Category::class,
SubCategory::class
);
}
But it gives error: Unknown column 'sub_categories.product_id'
You can install this external package staudenmeir/belongs-to-through to add the relationship you need.
class Product extends Model
{
public function subCategory()
{
return $this->belongsTo(SubCategory::class);
}
public functoin category()
{
return $this->belongsToThrough(Category::class, SubCategory::class);
}
}
class SubCategory extends Model
{
public functoin category()
{
return $this->belongsTo(Category::class);
}
}
class Category extends Model
{
public function subCategories()
{
return $this->hasMany(SubCategory::class);
}
public functoin products()
{
return $this->hasManyThrough(Product::class, SubCategory::class);
}
}
If you need to access Category directly from Product, and want to use laravels functions like $product->category()->attach($category->id) etc, then you need this dependency to achieve that.
If you are ok with doing:
$product->subCategory->category;
// or
$product->subCategory->category()->attach($category->id);
Then you don't need the dependency and you can exclude the category relationship on the Product model.

Laravel polymorphic relationship scope by pivot field

I have the following polymorphic relationship:
// User.php
public function regions()
{
return $this->morphedByMany('App\Region', 'relationship')->withPivot('relationship_level');
}
public function groups()
{
return $this->morphedByMany('App\Group', 'relationship')->withPivot('relationship_level');
}
The pivot table is as follows:
id | user_id | relationship_id | relationship_type | relationship_level
1 | 12 | 8 | App\Region | master
2 | 18 | 12 | App\Group | fan
Is there any way (preferably as scope) where I can get every user who has level "master" when this user can have many relationship level to many relationship_type.
Using the existing relationships:
User::whereHas('groups', function ($query) {
$query->where('relationship_level', 'master');
})->orWhereHas('regions', function ($query) {
$query->where('relationship_level', 'master');
})->get();
Using a pivot model and a new relationship (faster):
class Relationship extends \Illuminate\Database\Eloquent\Relations\MorphPivot
{
//
}
class User extends Model
{
public function relationships()
{
return $this->hasMany(Relationship::class);
}
}
User::whereHas('relationships', function ($query) {
$query->where('relationship_level', 'master');
})->get();

How to translate pivot values with laravel-translatable?

I just started using laravel-translatable package from dimsav which enables to set and retrieve translated strings from the database using Eloquent models. It works great but I still have trouble translating pivot values from belongsToMany relationships.
I have a model called Combination defined as shown below:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Combination extends Model {
public function product() {
return $this->belongsTo('App\Product');
}
public function product_attributes() {
return $this->belongsToMany('App\Attribute')->withPivot('value');
}
}
Here is my Attribute model:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Dimsav\Translatable\Translatable;
class Attribute extends Model {
use Translatable;
public $translatedAttributes = ['name'];
}
class AttributeTranslation extends Model {
public $timestamps = false;
protected $fillable = ['name'];
}
For instance, I have a Product called "T-Shirt" with two Attributes:
Color
Size
This Product has two combinations:
Black / M
Black / L
These values are stored as pivot values in an intermediate table called attribute_combination like this:
+--------------+----------------+-------+
| attribute_id | combination_id | value |
|--------------+----------------+-------|
| 1 | 1 | Black |
| 2 | 1 | M |
| 1 | 2 | Black |
| 2 | 2 | L |
+--------------+----------------+-------+
I have no problem retrieving the translated attribute's name using $attribute->name but I can't find a way to retrieve the translated pivot values. I tried to create a table called attribute_combination_translations and its AttributeCombination model as shown below but it does not work.
namespace App;
use Illuminate\Database\Eloquent\Model;
use Dimsav\Translatable\Translatable;
class AttributeCombination extends Model {
use Translatable;
protected $table = 'attribute_combination';
public $translatedAttributes = ['value'];
}
class AttributeCombinationTranslation extends Model {
public $timestamps = false;
protected $fillable = ['value'];
}
Maybe anyone using this package could help me get through this?

Laravel 4.2.8 > many to many > create a new related model and attach > error

don´t get it why this error occurs when inserting a new zip-code and relate it to an existing company using laravels eloquent belongsToMany feature.
here is my setup:
Error
file: "...\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php"
line: 411
message: "postcode"
type: "Illuminate\Database\Eloquent\MassAssignmentException"
Insertcode
$postcode = new Postcode(array('postcode' => $data['plz']));
Company::find($data['id'])->postcodes()->save($postcode);
Company Model
class Company extends Eloquent {
public function postcodes()
{
return $this->belongsToMany('Postcode');
}
}
Postcode Model
class Postcode extends Eloquent {
public function companies()
{
return $this->belongsToMany('Company');
}
}
Table postcodes
| id | postcode |
Table company_postcode
| id | postcode_id | company_id |
Table companies
| id | name |
Does anybody know why this isn´t working?
The error says
MassAssignmentException
That is because you are trying to mass assign postcode
new Postcode(array('postcode' => $data['plz']));
So make sure you whitelist the postcode variable as being mass assignable
class Company extends Eloquent {
protected $fillable = array('postcode');
public function postcodes()
{
return $this->belongsToMany('Postcode');
}
}

Write to hasMany relationship with Eloquent ORM/Laravel

Question about Laravel's Eloquent ORM. I've had a look on SO already, apologies if I've missed a similar question.
I have a User model, and I'm trying to write an array of Permissions back to the UserPermissions model, via the relationship in the User model.
I've setup the hasMany link already, and can retrieve the correct data from the User object ($user->roles), but can't work out how to write back if it is at all possible.
This is my basic user model:
class User extends Eloquent {
protected $table = 'users';
public $timestamps = false;
protected function roles() {
return $this->hasMany('UserPermission');
}
}
and the UserPermission model:
class UserPermission extends Eloquent {
protected $table = 'users_permissions';
public $timestamps = false;
protected $fillable = ['role_id', 'user_id'];
}
At this stage, I've reverted to saving the User, and then running UserPermission::insert(), which allows an array to be passed, but I'd prefer to do it in one step if possible.
Anyone know if this is possible?
Thanks!
UPDATE:
Table structure is below for your perusal:
users table
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | 0 | auto_increment |
| username | varchar(255) | NO | | | |
+------------------+------------------+------+-----+---------+----------------+
users_roles table
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | 0 | auto_increment |
| name | varchar(255) | NO | | | |
| description | varchar(255) | YES | | NULL | |
| url_access | varchar(255) | NO | | | |
+------------------+------------------+------+-----+---------+----------------+
users_permissions table
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | 0 | auto_increment |
| role_id | int(10) unsigned | NO | | | |
| user_id | int(10) unsigned | NO | | | |
+------------------+------------------+------+-----+---------+----------------+
role_id relates to users_roles.id and user_id relates to users.id
As background logic, the users_roles table has a url_access column which contains a url. If the user is assigned to that role, they have access to the subpages from that url.
I do not really see why you are using hasMany relationship instead of belongsToMany. Actually it seems that your database structure is already such that is utilized by the belongsToMany relationship in Laravel.
My solution:
User.php
<?php
class User extends Eloquent {
public function roles() {
return $this->belongsToMany('Role');
}
protected $table = 'users';
protected $guarded = array('id', 'password');
}
Role.php
<?php
class Role extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
protected $table = 'roles';
protected $guarded = array('id');
}
The corresponding database tables should be: users, roles and role_user. These are according to Laravel's naming conventions in order to keelp things simple.
Now you may call the sync method and pass an array to it:
$user->roles()->sync(array(1, 2, 3));
The sync method is briefly described in the Eloquent ORM documentation.
Okay here is what you could try.
Define a many to many relationship in both of the models.
class UserPermission extends Eloquent {
protected $table = 'users_permissions';
public $timestamps = false;
protected $fillable = ['role_id', 'user_id'];
protected function users() {
return $this->belongsToMany('User');
}
}
Then, if you create a user, use laravel attach method to connect a user to a users_permission like so:
$user = User::find(1);
$user->roles()->attach(1);
Attaching the role with an ID of 1 to the user with an ID of 1.
This is how you will be able to either attach a role to a user or attach a user to a role if you are creating a user or updating one.
I really hope that this is of help to you. If not, feel free to ask me further. I have defined many to many relations just a few days ago with photos and tags so I am quite into it I would say.
Also, the laravel docs even have an example with users and roles:
http://laravel.com/docs/eloquent#many-to-many
From reading your question it "sounds like" you are asking the same question I ran into the other day.
I hope this helps enable to you "bulk update" the relationships while maintaining timestamps and avoiding duplicate relationships.
Maybe there is a better way. I'm sure of it. But this worked perfectly for what I was trying to accomplish.
*Warning: this is not tested code. In fact the exact solution I used myself with some search/replace to help relate to your question
Class User extends BaseModel {
// [...]
public function roles() {
return $this->belongsToMany('Role');
}
public function addUserRoles(Array $add_user_role_ids) {
/**
* Prevent Duplicate Relationships
*/
$existing_user_role_ids = $this->roles()->lists('user_role_id');
$add_user_role_ids = array_diff($add_user_role_ids, $existing_user_role_ids);
if ($add_user_role_ids == null) return false;
$add_user_role_ids = UserRole::whereIn('id', $add_user_role_ids)->lists('id');
if ($add_user_role_ids == null) return false;
/**
* Attach (Insert into Pivot Table)
*/
if ( count($add_user_role_ids) > 0 ) {
$this->UserRoles()->attach($add_user_role_ids);
// Update timestamp
$this->touch();
}
// Return successfully added user role ids Array
return $add_user_role_ids;
}
public function removeUserRoles(Array $user_role_ids)
{
$this->touch();
$this->roles()->detach($user_role_ids);
}
// [...]
}
Eloquent Docs
Find me on Twitter: #ErikOnTheWeb

Resources