Fire a trait model when updating relation with sync - laravel

Im using a "history" trait on my Laravel application, to store changes on edited rows. But I have a problem that my relations on the model, is not firing the Historyable trait. I have tried adding the trait on the relation models, but still, no recorded changes to those related models.
For example in my App\Game model, I have this relation to genre:
public function genres(){
return $this->belongsToMany(Genre::class);
}
And in my GameController, for updating the genre relation I do this:
public function update(Request $request, Game $game)
{
$game->genres()->sync($request->get('genre'));
}
The trait on App\Game is called Historyable and looks like this:
trait Historyable {
/**
* [bootHistoryable description]
* #return [type] [description]
*/
public static function bootHistoryable(){
static::updated(function(Model $model){
collect($model->getWantedChangedColums($model))->each(function ($change) use ($model) {
$model->saveChange($change);
});
});
}
/**
* [save description]
* #return [type] [description]
*/
protected function saveChange(ColumnChange $change){
$this->history()->create([
'changed_column' => $change->column,
'changed_value_from' => $change->from,
'changed_value_to' => $change->to,
'user_id' => Auth::user()->id
]);
}
/**
* [getWantedChangedColums description]
* #param Model $model [description]
* #return [type] [description]
*/
protected function getWantedChangedColums(Model $model){
return collect(
array_diff(
Arr::except($model->getChanges(), $this->ignoreHistoryColumns()),
$original = $model->getOriginal()
)
)->map(function($change, $column) use ($original){
return new ColumnChange($column, Arr::get($original, $column), $change);
});
}
/**
* [history description]
* #return [type] [description]
*/
public function history(){
return $this->morphMany(History::class, 'historyable')->latest();
}
/**
* [ignoreHistoryColumns description]
* #return [type] [description]
*/
public function ignoreHistoryColumns() {
return [
'updated_at',
'password'
];
}
}
How can I fire the Historyable trait?

Related

How to check if many-to-many relation already exists in create and update

Every time I create a new book or update it with the same author, a new instance of the same author creates in DB
This is my codes here
Here is the BooksController
<?php
namespace App\Http\Controllers;
use App\Models\Author;
use App\Models\Book;
use Illuminate\Http\Request;
class BooksController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$books = Book::orderBy('created_at', 'desc')->with('authors')->paginate(5);
return view('books.index', [
'books' => $books
]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('books.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'author_name' => 'required',
'title' => 'required',
'release_year' => 'required|numeric',
'status' => 'required',
]);
I think I need to check here
// check if author already exists..
$authors = Author::all();
foreach($authors as $a){
if($a->name == $request->input('author_name')){
$author = $a;
}else{
}
}
Here if I have Glukhovski in the database and create a new book with the same author, another Glukhovski is added in the database, so I think there must be a way to check and if the author already exists, assign it to the book through the pivot table?
$author = Author::create([
'name' => $request->input('author_name')
]);
$book = Book::create([
'title' => $request->input('title'),
'release_year' => $request->input('release_year'),
'status' => $request->input('status')
]);
$book->authors()->attach($author->id);
return redirect('/books');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$book = Book::find($id);
return view('books.show')->with('book', $book);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$book = Book::find($id);
return view('books.edit')->with('book', $book);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$request->validate([
'author_name' => 'required',
'title' => 'required',
'release_year' => 'required',
'status' => 'required',
]);
... and here as well
// check if author already exists.....
//
$author = Author::create([
'name' => $request->input('author_name')
]);
$book = Book::find($id);
$book -> update([
'title' => $request->input('title'),
'release_year' => $request->input('release_year'),
'status' => $request->input('status')
]);
$book->authors()->sync($author->id);
return redirect('/books');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
Book::find($id)->delete();
return redirect('books');
}
}
Pivot table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAuthorBookTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('author_book', function (Blueprint $table) {
$table->id();
$table->foreignId('author_id');
$table->foreignId('book_id');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('author_book');
}
}
you can check first for author in this way before you create the author, if author doesn't exist, it will create a new one
$author = Author::where('name',$request->input('author_name'))->first();
if(!$author){
$author = Author::create([
'name' => $request->input('author_name')
]);
}

Laravel Datatable only searchs ID

I generated my Laravel CRUD views with InfyOm, which uses Datatables to present it. It comes with a search field by default, but when I try to search it only searches by ID. I can't find how I can set to search in the other fields too. I can't find any documentation about how to implement this. It seems that it has something to do with this, but I didn't get it. How can I make this?
Here is my Datatable class:
<?php
namespace App\DataTables;
use App\Models\SubscriptionStatus;
use Yajra\DataTables\Services\DataTable;
use Yajra\DataTables\EloquentDataTable;
class SubscriptionStatusDataTable extends DataTable
{
/**
* Build DataTable class.
*
* #param mixed $query Results from query() method.
* #return \Yajra\DataTables\DataTableAbstract
*/
public function dataTable($query)
{
$dataTable = new EloquentDataTable($query);
return $dataTable->addColumn('action', 'subscription_statuses.datatables_actions');
}
/**
* Get query source of dataTable.
*
* #param \App\Models\Post $model
* #return \Illuminate\Database\Eloquent\Builder
*/
public function query(SubscriptionStatus $model)
{
return $model->newQuery();
}
/**
* Optional method if you want to use html builder.
*
* #return \Yajra\DataTables\Html\Builder
*/
public function html()
{
return $this->builder()
->columns($this->getColumns())
->minifiedAjax()
->addAction(['width' => '80px', "title" => "Ações"])
->parameters([
'dom' => 'Bfrtip',
'order' => [[0, 'desc']],
'buttons' => [
'export',
'print',
'reset',
'reload',
],
]);
}
/**
* Get columns.
*
* #return array
*/
protected function getColumns()
{
return [
['data' => 'name', 'title' => 'Nome'],
['data' => 'description', 'title' => 'Descrição'],
['data' => 'expire_days', 'title' => 'Tempo para Expirar'],
];
}
/**
* Get filename for export.
*
* #return string
*/
protected function filename()
{
return 'subscription_statusesdatatable_' . time();
}
}

Trying to get property of non-object. Error in laravel

I'm kinda new at laravel and need your help.
I have this IR model :
class IR extends Model
{
//
protected $fillable=['irnum','date','subject','cause','facts','as','at','rec','user_id'];
protected $casts=['user_id'=>'int'];
public function user()
{
return $this->belongsTo(user::class);
}
public static $rules =array (
'date'=>'required',
'status'=>'required|min:10',
'cause' => 'required|min:10',
'facts' => 'required|min:10',
'ir-as' => 'required|min:10',
'rec' => 'required|min:10',
'ir-at' => 'required|min:10',
);
}
and route:
Route::group(['middleware' => ['web']], function () {
Route::get('/', function () {
return view('welcome');
})->middleware('guest');
Route::resource('tasks','TaskController');
Route::get('ir',function ()
{
return View::make('tasks/ir');
});
Route::resource('irs','IRController');
Route::auth();
});
and this is my controller :
class IRController extends Controller
{
/**
* The task repository instance.
*
* #var TaskRepository
*/
protected $irs;
/**
* Create a new controller instance.
*
* #param TaskRepository $tasks
* #return void
*/
public function __construct(IRRepository $irs)
{
$this->middleware('auth');
$this->irs = $irs;
}
/**
* Display a list of all of the user's task.
*
* #param Request $request
* #return Response
*/
public function index(Request $request)
{
return view('tasks.ir',[
'irs' => $this->irs->forUser($request->user()),
]);
}
/**
* Create a new task.
*
* #param Request $request
* #return Response
*/
public function create()
{
return View::make('irs.create');
}
public function store(Request $request)
{
$request->user_id=Auth::user()->id;
$input =$request->all();
$validation=Validator::make($input, IR::$rules);
if($validation->passes())
{
IR::create($input);
return Redirect::route('tasks.ir');
}
return Redirect::route('tasks.ir')
->withInput()
->withErrors($validation)
->with('message','There were validation errors.');
}
/**
* Destroy the given task.
*
* #param Request $request
* #param Task $task
* #return Response
*/
public function destroy(Request $request, IR $irs)
{
}
}
I really dont know what causes to throw this error.
Error throws when i add Incident report.
Pls help.
New at laravel
You're saying you get an error when you're trying to add an incident report or IR, so I assume problem is in a store() action.
I can see only one potential candidate for this error in a store() action:
Auth::user()->id;
Add dd(Auth::user()); before this clause and if it will output null, use check() method, which checks if any user is authenticated:
if (Auth::check()) {
Auth::user->id;
}

ErrorException in SessionGuard.php | Getting error when trying to register user while creating new order

I want user to register and also buy a package. To do that I took input for registration details and package details. Now when I'm processing order to save package details in session and register, I get this error : Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\View\View given, called in C:\xampp\htdocs\rename\app\Traits\OrderRegister.php on line 63 and defined. I'm using an trait to register user and return back to function when registration is complete.
OrderController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Package;
use App\ListingType;
use Illuminate\Support\Facades\Auth;
use App\Order;
use Carbon\Carbon;
use App\Traits\OrderRegister;
class OrderController extends Controller
{
use OrderRegister;
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index($type)
{
$listingtype = ListingType::where('type', '=', $type)->first();
if ($listingtype) {
$packages = $listingtype->packages()->get();
return view('packages.index', compact('packages'));
}
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create($id)
{
$package = Package::where('id', '=', $id)->first();
if (Auth::check()) {
return view('order.create_loggedin', compact('package'));
}
else {
return view('order.create_register', compact('package'));
}
}
/**
* Process a new order request. Store order values in session.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function process(Request $request)
{
$order = ['package_id' => $request->package_id, 'order_qty' => $request->no_of_listing];
session(['order' => $order]);
if (Auth::guest()) {
return $this->register($request); // need to check session for orders available in OrderRegister trait.
}
return $this->store($request);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if($request->session()->has('order')) {
$package = Package::where('id', '=', $request->package_id )->first();
if($request->user() == Auth::user()) {
for( $n=1;$n<=$request->no_of_listing;$n++) {
$order = new Order;
$order->package_id = $request->package_id;
$order->user_id = Auth::user()->id;
$order->expire_at = Carbon::now()->modify('+'.$package->duration_in_months.' months');
$order->save();
}
return redirect('/');
}
}
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
trait : OrderRegister.php
<?php
namespace App\Traits;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Validator;
trait OrderRegister
{
use RedirectsUsers;
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'username' => 'required|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'username' => $data['username'],
'password' => bcrypt($data['password']),
]);
$user->profile()->save(new UserProfile);
return $user;
}
/**
* Execute the job.
*
* #return void
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
Auth::guard($this->getGuard())->login($this->create($request->all()));
return $this->store($request);
}
/**
* Get the guard to be used during registration.
*
* #return string|null
*/
protected function getGuard()
{
return property_exists($this, 'guard') ? $this->guard : null;
}
}
I could not find any solution for this error so created my own thread for the first time please someone help.
It throws an error because you are trying to login a vue.
in your OrderController.php you are using create method which return a view.
this method will override the create method on your trait.
So you have something like this :
Auth::guard($this->getGuard())->login(/* A view */);
you can at least rename the method on the trait from create to createUser for example.
then you call it from the guard like this :
Auth::guard($this->getGuard())->login($this->createUser($request->all()));

laravel 4 - inserting of multiple fields in array

The following function in laravel stores my form input. I can't get it to store anything other than the author id and the title. It just won't store the keywords.
Below is the function in my Postcontroller.php
public function store()
{
$input = Input::all();
$rules = array(
'title' => 'required',
'text' => 'required',
);
$validation = Validator::make($input, $rules);
if ($validation->fails()) {
return Redirect::back()->withErrors($validation)->withInput();
} else {
// create new Post instance
$post = Post::create(array(
'title' => $input['title'],
'keywords' => $input['keywords'],
));
// create Text instance w/ text body
$text = Text::create(array('text' => $input['text']));
// save new Text and associate w/ new post
$post->text()->save($text);
if (isset($input['tags'])) {
foreach ($input['tags'] as $tagId) {
$tag = Tag::find($tagId);
$post->tags()->save($tag);
}
}
// associate the post with user
$post->author()->associate(Auth::user())->save();
return Redirect::to('question/'.$post->id);
}
}
Post.php (model)
<?php
class Post extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'posts';
/**
* Whitelisted model properties for mass assignment.
*
* #var array
*/
protected $fillable = array('title');
/**
* Defines a one-to-one relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-one
*/
public function text()
{
return $this->hasOne('Text');
}
/**
* Defines an inverse one-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-many
*/
public function author()
{
return $this->belongsTo('User', 'author_id');
}
/**
* Defines a many-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#many-to-many
*/
public function tags()
{
return $this->belongsToMany('Tag');
}
/**
* Defines an inverse one-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-many
*/
public function category()
{
return $this->belongsTo('Category');
}
/**
* Defines a polymorphic one-to-one relationship.
*
* #see http://laravel.com/docs/eloquent#polymorphic-relations
*/
public function image()
{
return $this->morphOne('Image', 'imageable');
}
/**
* Defines a one-to-many relationship.
*
* #see http://laravel.com/docs/eloquent#one-to-many
*/
public function comments()
{
return $this->hasMany('Comment');
}
}
You are stopping the mass assignment of keywords with your model settings.
Change
protected $fillable = array('title');
to
protected $fillable = array('title', 'keywords');

Resources