Comment/Post system in Laravel - laravel

I can't seem to get relationships concrete in my head with Laravel. Having tried to follow the docs for eloquent orm, I still can't get my foreign keys to mean something (I update them manually). Right now I am trying to get a bulletin board system to work. A user can create a bulletin post, and here it is working in my controller:
public function editPost($id)
{
$user = User::find($id);
$user->bulletin = new Bulletin;//new post
$user->bulletin->creator_id = $id;//why doesn't it automatically update given the relationship?
$user->bulletin->type = Input::get('type');
$user->bulletin->title = Input::get('title');
$user->bulletin->content = Input::get('bulletinEdit');
$user->bulletin->save();
if(Input::hasFile('bulletinImage')){
$extension = Input::file('bulletinImage')->getClientOriginalExtension();
$fileName = str_random(9).'.'.$extension;
$user->bulletin->photo = new Photo;
$user->bulletin->photo->user_id = $id;
$user->bulletin->photo->type = Input::get('type');
$user->bulletin->photo->filename = $fileName;
$user->bulletin->photo->touch();
$user->bulletin->photo->save();
Input::file('bulletinImage')->move('public/images/bulletin/',$fileName);
}
return Redirect::to('bulletin');
}
If I have the relationship set up properly, shouldn't the creator_id be updated automatically? Here is what I have in my models:
Bulletin
<?php
class Bulletin extends Eloquent {
public function creator()
{
return $this->belongsTo('User');
}
public function comments()
{
return $this->hasMany('Comment');
}
public function type()
{
//if 1 then, etc
}
public function photos(){
return $this->hasMany('Photo');
}
}
User
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
/**
* The database table used by the model.
*
* #var string
*/
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
public function tags()
{
//TO REMOVE RECORD
//User::find(1)->tags()->detach();
return $this->belongsToMany('Tag');
}
public function createUser()
{
$password = Hash::make('secret');
}
public function bulletin()
{
return $this->hasMany('Bulletin','creator_id');
}
public function profile()
{
return $this->hasOne('Profile');
}
}
Could anybody give me some tips on tightening this up?

The way you are doing it should work, you are just using more code and Eloquent has some methods to help you attach relationships, so I would try something like this:
public function editPost($id)
{
$user = User::find($id);
// Create a new bulletin, passing the necesssary data
$bulletin = new Bulletin(Input::only(['type', 'title', 'bulletinEdit']));
// Attach the bulletin model to your user, Laravel should set the creator_id itself
$bulletin = $user->bulletin()->save($bulletin);
...
return Redirect::to('bulletin');
}
In your model, you'll have to:
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $fillable = ['type', 'title', 'bulletinEdit'];
...
}
So Laravel doesn't give you a MassAssignmentException.

Related

lararvel uuid as primary key

I'm trying to set an uuid as primary key in a Laravel Model. I've done it setting a boot method in my model as stablished here so I don't have to manually create it everytime I want to create and save the model. I have a controller that just creates the model and saves it in database.
It is saved correctly in database but when controller returns the value of the id is always returned with 0. How can I make it to actually return the value that it is creating in database?
Model
class UserPersona extends Model
{
protected $guarded = [];
protected $casts = [
'id' => 'string'
];
/**
* Setup model event hooks
*/
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$uuid = Uuid::uuid4();
$model->id = $uuid->toString();
});
}
}
Controller
class UserPersonaController extends Controller
{
public function new(Request $request)
{
return UserPersona::create();
}
}
You need to change the keyType to string and incrementing to false. Since it's not incrementing.
public $incrementing = false;
protected $keyType = 'string';
Additionally I have an trait which I simply add to those models which have UUID keys. Which is pretty flexible. This comes originally from https://garrettstjohn.com/articles/using-uuid-laravel-eloquent-orm/ and I added some small adjustments to it for issues which I have discovered while using it intensively.
use Illuminate\Database\Eloquent\Model;
use Ramsey\Uuid\Uuid;
/**
* Class Uuid.
* Manages the usage of creating UUID values for primary keys. Drop into your models as
* per normal to use this functionality. Works right out of the box.
* Taken from: http://garrettstjohn.com/entry/using-uuids-laravel-eloquent-orm/
*/
trait UuidForKey
{
/**
* The "booting" method of the model.
*/
public static function bootUuidForKey()
{
static::retrieved(function (Model $model) {
$model->incrementing = false; // this is used after instance is loaded from DB
});
static::creating(function (Model $model) {
$model->incrementing = false; // this is used for new instances
if (empty($model->{$model->getKeyName()})) { // if it's not empty, then we want to use a specific id
$model->{$model->getKeyName()} = (string)Uuid::uuid4();
}
});
}
public function initializeUuidForKey()
{
$this->keyType = 'string';
}
}
Hope this helps.
Accepted answer not worked for me on Laravel 9, but this way worked perfect, you can try it:
1- Create new Trait Class in project path app/Traits/IdAsUuidTrait.php (if you not found Traits folder create it, this is full code of this Class:
<?php
namespace App\Traits;
use Illuminate\Support\Str;
trait IdAsUuidTrait
{
public function initializeIdAsUuidTrait(): void
{
$this->keyType = 'string';
$this->id = Str::orderedUuid()->toString();
}
}
2- In any model you want to make id as UUID just call trait like this:
use App\Traits\IdAsUuidTrait;
class YourModelName extends Model
{
use IdAsUuidTrait;
...
That is it, now try to create, select, update any row in database by this model...

Undefined property in laravel framework accessor calling belongsTo

I need your help.
I'm working with Laravel Framework and I have a trouble with a belongsTo relationship.
My project have to tables, address book and delivery types, the columns in tables are:
address_book
id
name
mail
delivery_1
deliverytype_id_1
delivery_2
deliverytype_id_2
...
delivery_types
id
name
...
The code of delivery types model is this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class DeliveryType extends Model
{
protected $table = 'delivery_types';
protected $guarded = ['id'];
}
This is the address book model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class AddressBook extends Model
{
protected $table = 'address_book'; // table
protected $guarded = ['id']; // primary key
protected $appends = ['delivery', 'actions']; // accessors
protected $delivery = '';
public function del1() {
return $this->belongsTo('App\DeliveryType', 'deliverytype_id_1', 'id')->withDefault();
}
public function del2() {
return $this->belongsTo('App\DeliveryType', 'deliverytype_id_2', 'id');
}
/**
* Accessor: get the actions column information.
*
* #return string
*/
public function getActionsAttribute() {
$actions = '<a href='. route('admin.addressbook.show', $this->id) .'>'.
'show<i class="livicon" data-name="info" data-size="18" data-loop="true" data-c="#428BCA" data-hc="#428BCA" title="view contact"></i></a>';
return $actions;
}
/**
* Accessor: get the deliveries information.
*
* #return string
*/
public function getDeliveryAttribute () {
$deliveries = [
['val' => $this->delivery_1, 'type' => $this->del1()->name], //row error
['val' => $this->delivery_2, 'type' => $this->del2()->name]
];
foreach($deliveries as $delivery) {
$this->delivery = (strlen($delivery['val']) > 0) ?
$this->appendString($this->delivery, '<strong>'.$delivery['type'].'</strong> '.$delivery['val']) :
$this->delivery;
}
return $this->delivery;
}
protected function appendString(string $str, string $val) {
return (strlen($str) > 0) ? $str.'<br>'.$val : $val;
}
In the html page the data is loaded through ajax call to the controller function. This is the code of function:
public function data(Request $request) {
// Init data
$this->addressbooks = AddressBook::get(
['address_book.id',
'address_book.name',
'address_book.email',
'address_book.delivery_1',
'address_book.delivery_2');
// Return json array
header("Content-Type: application/json");
return $this->addressbooks;
}
When the page call the function through ajax, the framework return the error "Undefined property" in the accessor getDeliveryAttribute, where I try to call relationship belongs to about delivery type ID and its reference in the delivery types table.
What I'm doing wrong? Thanks in advance to those who can help me.
Here is how I would write the AddressBook model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
//use Illuminate\Support\Facades\Log;
class AddressBook extends Model
{
protected $table = 'address_book'; // table
//protected $guarded = ['id']; // primary key
// always load these accessors
protected $appends = [
'delivery',
'actions',
];
protected $mail = '';
// No need for $delInfo, use $this->delivery (same data)
// protected $delInfo = '';
public function category() {
/*
You can use `AddressBookCategory::class` instead of `'App\DeliveryType'`
http://php.net/manual/en/migration55.new-features.php#migration55.new-features.class-name
Because models are in the same napespace, we don't need to write \App\AddressBookCategory
*/
return $this->belongsTo(AddressBookCategory::class, 'address_book_category_id', 'id');
}
public function deliveryType1() {
return $this->belongsTo(DeliveryType::class, 'deliverytype_id_1', 'id')
/*
Specify empty string for the name, so that when we access
$this->deliveryType1->name it's equal ''
*/
->withDefault(['name' => '']);
}
public function deliveryType2() {
return $this->belongsTo(DeliveryType::class, 'deliverytype_id_2', 'id')
->withDefault(['name' => '']);
}
/**
* Accessor: get the actions column information.
*
* Access by using: $this->action
*
* #return string
*/
public function getActionsAttribute() {
// moved this into multi line, easier to read
return '<a href='. route('admin.addressbook.show', $this->id) .'>'
.'show'
.'<i class="livicon" data-name="info" data-size="18" data-loop="true" data-c="#428BCA" data-hc="#428BCA" title="view contact"></i>'
.'</a>';
}
/**
* Accessor: get the deliveries information
*
* Access by using: $this->delivery
*
* #return string
*/
public function getDeliveryAttribute () {
// I've updated logic here, it should be easier to read...
$delivery = [];
if ( ! empty($this->delivery_1) ) {
$delivery[] = '<strong>'.$this->deliveryType1->name.'</strong> '.$this->delivery_1;
}
if ( ! empty($this->delivery_2) ) {
$delivery[] = '<strong>'.$this->deliveryType2->name.'</strong> '.$this->delivery_2;
}
// join array elements with a string `<br>`
return implode('<br>', $delivery);
}
}

How do I load a collection in a model then query it with the query builder

I have create a morphMany relationship for ratings and I'm having a problem loading the ratings relationship data inside the model using the model->load or model::with method both of them aren't letting me use the collections model builder.
if I do this inside a method of a model it throws an error:
$all = this->ratings()->get();
return $all;
Call to undefined method Illuminate\Database\Query\Builder::ratingInfo()
I need the ratings query builder so I can then query and filter the results but It's not using the query builder and even if I make this a scope it's still throws the same error.
all code:
class Product extends Model
{
use Rateable;
protected $table = "products";
protected $fillable = [
'title',
'sku',
'quantity',
'unit_price',
'created_by', 'updated_by'
];
public function created_by() {
return $this->belongsTo('App\User', 'created_by', 'id');
}
public function updated_by() {
return $this->belongsTo('App\User', 'updated_by', 'id');
}
public function ratings() {
return $this->morphMany('App\Rating', 'rateable');
}
public function ratingInfo() {
$all = $this->ratings()->get() error using get request for eager loading;
// i want to query like this
$two_star = $all->filter(function ($item, $key) {
return $item->rating === 2;
});
return $all;
}
}
public function show($id) {
$product = Product::findOrFail($id);
// it doesn't seem to matter if use the keyword ::with('ratingInfo')
$product->load('ratingInfo', 'created_by', 'updated_by');
return response()->json($product, 200, ['Content-Length' => strlen(json_encode($product))]);
}
class Rating extends Model
{
protected $table = 'ratings';
protected $fillable = ['rating', 'comment', 'user_id', 'rateable_id', 'rateable_type'];
public function rating()
{
return $this->morphTo();
}
}
Using phone numbers and user and companies as an example:
class PhoneNumber extends Model
{
/**
* Get all of the owning callable models.
*/
public function callable()
{
return $this->morphTo();
}
}
class Company extends Model
{
/**
* Get all of the model's phone numbers.
*
* #return mixed
*/
public function phoneNumbers()
{
return $this->morphMany(PhoneNumber::class, 'callable');
}
}
class User extends Model
{
/**
* Get all of the model's phone numbers.
*
* #return mixed
*/
public function phoneNumbers()
{
return $this->morphMany(PhoneNumber::class, 'callable');
}
}
To save a phone number to a user or company would be like this:
$phoneNumber = new PhoneNumber(['number' => '555-555-5555']);
$user->phoneNumbers()->save(phoneNumber);
$phoneNumber = new PhoneNumber(['number' => '555-555-5555']);
$company->phoneNumbers()->save(new PhoneNumber(phoneNumber));
Then to access the phone number collections associated with each, simply:
$user->phoneNumbers // this is a Collection
$company->phoneNumbers // this is a Collection
$user->phoneNumbers->count() // access to all Collection methods as this point

Laravel - how to makeVisible an attribute in a Laravel relation?

I use in my model code to get a relation
class User extends Authenticatable
{
// ...
public function extensions()
{
return $this->belongsToMany(Extension::class, 'v_extension_users', 'user_uuid', 'extension_uuid');
}
// ...
}
The Extension has field password hidden.
class Extension extends Model
{
// ...
protected $hidden = [
'password',
];
// ...
}
Under some circumstances I want to makeVisible the password field.
How can I achieve this?
->makeVisible([...]) should work:
$model = \Model::first();
$model->makeVisible(['password']);
$models = \Model::get();
$models = $models->each(function ($i, $k) {
$i->makeVisible(['password']);
});
// belongs to many / has many
$related = $parent->relation->each(function ($i, $k) {
$i->makeVisible(['password']);
});
// belongs to many / has many - with loading
$related = $parent->relation()->get()->each(function ($i, $k) {
$i->makeVisible(['password']);
});
Well, I got the idea from https://stackoverflow.com/a/38297876/518704
Since my relation model Extension::class is called by name in my code return $this->belongsToMany(Extension::class,... I cannot even pass parameter to it's constructor.
So to pass something to the constructor I may use static class variables.
So in my Extension model I add static variables and run makeVisible method.
Later I destruct the variables to be sure next calls and instances use default model settings.
I moved this to a trait, but here I show at my model example.
class Extension extends Model
{
public static $staticMakeVisible;
public function __construct($attributes = array())
{
parent::__construct($attributes);
if (isset(self::$staticMakeVisible)){
$this->makeVisible(self::$staticMakeVisible);
}
}
.....
public function __destruct()
{
self::$staticMakeVisible = null;
}
}
And in my relation I use something like this
class User extends Authenticatable
{
...
public function extensions()
{
$class = Extension::class;
$class::$staticMakeVisible = ['password'];
return $this->belongsToMany(Extension::class, 'v_extension_users', 'user_uuid', 'extension_uuid');
}
...
}
The highest voted answer didn't seem to work for me (the relations attribute seems to be a protected array now so can't be used as a collection in #DevK's answer), I instead used:
$parent->setRelation('child', $parent->child->first()->setVisible(['id']));

Trouble getting attribute of relation in Laravel

I'm having a trouble with a relation in Laravel 5. the thing is that I have a table User and that user belongs to a Group for that, in the User model I have this:
public function group(){
return $this->belongsTo('App\models\Group');
}
The model Group have this attributes: name,unity,level, init_date. I also put there a default function to return a group as String, this is the code:
public function __toString(){
return $this->name.' Unity '.$this->unity;
}
So, the thing that in a view a have many users and for each of them I want to display the unity, name,date. When I call $user->group it returns me correctly the name and the unity in a String (because the _toString function) that means that he is really querying the group perfectly, but then, when I want to access a simple attribute as unity,date,or name with $user->group->name Laravel gives me this error:
Trying to get property of non-object
I even tried $user->group()->name then I gets: Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$name
Edited:
The model User:
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'users';
protected $fillable = ['email', 'password','estate','filial_id','perfil_id','rol','cat_teacher'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function __toString(){
return $this->email;
}
public function filial(){
return $this->belongsTo('App\models\Filial');
}
public function perfil(){
return $this->belongsTo('App\models\Perfil','perfil_id');
}
public function grupo(){
return $this->belongsTo('App\models\Group','group_id','id');
}
}
The model Group:
class Group extends Model {
protected $table = 'groups';
protected $fillable = ['name','unity','date'];
public function filiales() {
return $this->belongsTo('App\models\Filial');
}
public function teacher(){
return $this->belongsTo('App\models\User','teacher_id');
}
public function users() {
return $this->hasMany('App\models\User');
}
}
Then, in the controller I made a dd($users) and there not appear the relations, appears other relations but not this one. In the view I want to print some of the attributes in a table, for that I have:
<td>{{$user->group}}</td>
<td>{{$user->group->unity}}</td>
The first line works perfectly, and I donĀ“t know why.
The reason you're unable to return your group's name is that ->group() returns an instance of the query builder, and not an eloquent collection/object. Since a user belongs to a single group, modify your code in one of these two ways:
public function group(){
return $this->belongsTo('App\models\Group')->first();
}
And then access the group using one of the following methods:
$user = User::with("group")->where("id", "=", 1)->first();
$group = $user->group;
echo $group->name;
// OR
$user = User::where("id", "=", 1)->first();
$group = $user->group();
echo $group->name;
Or, leave the group() function as it is and access ->group()->first() on your $user object:
$user = User::where("id", "=", 1)->first();
$group = $user->group()->first();
echo $group->name;
Any of the above methods should properly return your group object's name (or other attributes). Check the Eloquent Documentation for detailed explanations on how to access these objects.

Resources