How do insert data into pivot table with columns without models? - laravel-5.4

I'm learning laravel pivot table and here's what I'm doing. I have a student and subject model with many to many relationship. In my pivot table i have included columns for test1, test2 and test3 so that i can use it to store the student's score for each subject. These are my models
class Student extends Model
{
protected $guarded = ['id'];
public function subjects()
{
return $this->belongsToMany(Subject::class);
}
}
class Subject extends Model
{
protected $guarded = ['id'];
public function students()
{
return $this->belongsToMany(Student::class);
}
}
This is my migration
public function up()
{
Schema::create('subjects', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->timestamps();
});
Schema::create('student_subject', function (Blueprint $table) {
$table->integer('student_id');
$table->integer('subject_id');
$table->primary(['student_id', 'subject_id']);
$table->integer('test1')->nullable();
$table->integer('test2')->nullable();
$table->integer('test3')->nullable();
});
}
This is where it all got complicated for me. When a student record is created, user is redirected to an enroll page where subjects are selected for the student.
This is my StudController#store
public function store(Request $request)
{
$student = Student::create(request()->all());
Session::flash('status', "New student's record was added successfully");
Session::put('firstname', request('firstname'));
Session::put('lastname', request('lastname'));
Session::put('student_id', $student->id);
Session::put('class', $student->class_admitted);
return redirect('/enroll');
}
This is the enroll form
<form class="form-horizontal" role="form" method="POST" action="/enroll">
{{ csrf_field() }}
<input type="" name="student_id" value="{{ Session::get('student_id')}}" hidden>
<div class="col-md-6 form-group subjectList">
<ul>
#foreach ($subjects as $subject)
<li><label class="checkbox-inline"><input type="checkbox" name="subject_id[]" value="{{ $subject->id }}"> {{ ucwords($subject->name) }}</label></li>
#endforeach
</ul>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Enroll
</button>
</div>
</div>
</form>
And this is my EnrollController#store
public function store(Request $request)
{
//dd($request);
$student = request('student_id');
foreach ($request->input('subject_id') as $subject) {
$student->subjects()->attach($subjects);
}
}
I'm confused as to how I can do insert into the pivot table.

You can add an array in your attach() method, like this:
->attach($subjectId, ['test1' => 1, 'test2' => 2]);
The attach() method will create the entry in the pivot table, the additional attributes will be added.
You can also pass an array of subjects to attach(), like this:
->attach([1 => ['test1' => 1, 'test2' => 2], 2 => ['test1' => 3, 'test2' => 4]]);
And when you need to update the pivot data you can use sync().
As far as I can see now, you do not have anything in your form besides the subject, so I assume you want to update the pivot data later on.
Also, you might want to add some additional validation there on both the student and the subjects.
public function store(Request $request)
{
// making sure student exists
$student = Student::findOrFail(request('student_id'));
$subjectIds = Subject::whereIn('id', $request->input('subject_id', []))
->get()
->pluck('id')
->all();
$student->subjects()->attach($subjectIds);
// you can also use sync here, that way it will add new subjects, keep the ones that already exist (and are posted) and remove subjects not in post
// $student->subjects()->sync($subjectIds);
}

Related

One to Many relationship, sort and filter children

I want to display all posts which like the user. OK. I can use this:
$user = User::where('slug', $user->slug)
->first();
dd($user->likes);
But it doesn't what I want to do. Which any post have to be accept by moderator (->where('accept', 1)) and orderign (->orderBy('created_at', 'desc')).
Who know how I can do that?
Currently I have 2 models. My relationships:
//Post
public function likes(){
return $this->hasMany('App\Like');
}
//Likes
public function post(){
return $this->belongsTo('App\Post');
}
//migrate of likes look like this
Schema::create('likes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->integer('post_id');
$table->timestamps();
});
How I can solve my problem?
You could set up an M:N relationship between User and Post using Likes as pivot.
# User model
public function likes()
{
return $this->hasMany(Likes::class, 'user_id');
}
public function liked_posts()
{
return $this->belongsToMany(Post::class, 'likes', 'user_id', 'post_id');
}
# Likes model
public function post()
{
return $this->belongsTo(Post::class);
}
You could set it up like you have, User has many Likes belongs to Post.
// Using only likes and Likes's post relationship
$user = User::with(['likes.post' => function ($posts) {
$posts->where('accept', 1)->orderBy('created_at', 'desc');
}])->where('slug', $slug)->first();
Or you could use the M:N relationship.
// Using the liked_posts relationship
$user = User::with(['liked_posts' => function ($posts) {
$posts->where('accept', 1)->orderBy('created_at', 'desc');
}])->where('slug', $slug)->first();

Doesn't have a default value error ! Laravel

I have referred all the other questions asked and did what they have told. Still i cant get rid of default_value error. I have added multiple connections. So i have 3 databases : Users , companya , companyb.
Company-A and Company-B has same structure.
Stocks have tag_no as primary key and i have specified it in model too.
Inside Stock model I have created a constructor to dynamically switch models based on users company.
Even after all this i keep getting this error.
I tried changing strict to false inside database.php but.. all the entries are showing value 0. So I stopped trying that.
So what can i do to solve this. Please help!
Below is my schemas:
For Users:
Schema::connection('mysql')->create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('company')->default('companya');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->string('user_type',50)->default('user');
$table->rememberToken();
$table->timestamps();
});
For company-A and company-B:
Schema::connection('companya')->create('stocks', function (Blueprint $table) {
$table->string('tag_no')->index();
$table->string('stock_type');
$table->timestamps();
});
Here is my Stock Model:
class Stock extends Model
{
protected $primaryKey = 'tag_no';
public $incrementing = false;
protected $fillable = [
'tag_no',
'stock_type',
];
public function __construct() {
if ( Auth::check() ) {
$this->connection = Auth::user()->company;
}
}
}
Code for store function:
public function store(Request $request)
{
if(Auth::check()){
if (Stock::where('tag_no','=',$request->input('tag_no'))->exists()) {
return back()->withInput()->with('errors', 'Tag number already used!');
}
$stock = Stock::create([
'tag_no' => $request->input('tag_no'),
'stock_type' => $request->input('stock_type'),
]);
}
if($stock){
return redirect()->route('stocks.index', ['stocks'=> $stock->tag_no])
->with('success' , 'Stock created successfully');
}
return back()->withInput()->with('errors', 'Error creating new Stock');
}
Just changed create to insert and removed stocks parameter.
public function store(Request $request)
{
if(Auth::check()){
if (Stock::where('tag_no','=',$request->input('tag_no'))->exists()) {
return back()->withInput()->with('errors', 'Tag number already used!');
}
$stock = Stock::insert([
'tag_no' => $request->input('tag_no'),
'stock_type' => $request->input('stock_type'),
]);
}
if($stock){
return redirect()->route('stocks.index')
->with('success' , 'Stock created successfully');
}
return back()->withInput()->with('errors', 'Error creating new Stock');
}

Integrity constraint violation: 1048 Column 'post_id' cannot be null

I'm using laravel 5.5 and im trying to add a comment to a post and i get the following error when i submit to the form
"SQLSTATE[23000]: Integrity constraint violation: 1048 Column
'post_id' cannot be null (SQL: insert into comments (comment_body,
user_id, post_id, updated_at, created_at) values (sdsd, 1, ,
2017-12-03 12:29:58, 2017-12-03 12:29:58))
im going to be using: <% %> is for angular, just letting everyone know.
In tinker this works
Comment::create(['comment_body' => 'this works', 'user_id'=> 1, 'post_id'=>8]);
**Route*
Route::post('post/comment', 'CommentController#create');
Post Model
use App\User;
use App\Like;
use App\Comment;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Post extends Authenticatable
{
protected $fillable = [
'title',
'body',
'user_id',
'created_at',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function likes()
{
return $this->hasMany('App\Like');
}
public function comments()
{
return $this->hasMany('App\Comment');
}
Comment Model
class Comment extends Model
{
protected $fillable = [
'comment_body',
'user_id',
'post_id'
];
public function user()
{
return $this->belongsTo('App\User');
}
public function post()
{
return $this->belongsTo('App\Post');
}
}
CommentConroller
public function create(Request $request, Post $post)
{
$data = request()->validate([
'comment_body' => 'required|max:1000'
]);
$data['user_id'] = auth()->user()->id;
$data['name'] = auth()->user()->name;
$data['post_id'] = $post->id;
$post = Comment::create($data);
$response = new Response(json_encode($data));
$response->headers->set('Content-Type', 'application/json');
if(!$response){
return 'something went wrong';
}
return response()->json($data);
}
Html
<div class="comment-class animated bounceInUp" ng-show="writecomment">
<div class="panel-body">
<ng-form ng-model="commentForm" name="commentForm" method="POST" novalidate>
<div class="form-group">
<label>Write a Comment</label>
<textarea ng-model="post.comment" type="text" class="form-control" name="comment_body" cols="2" rows="2"></textarea>
</div>
<button id="eli-style-button" ng-click="addComment(post)" class="btn btn-primary" type="submit">Submit</button>
</form>
</div>
<!-- END Comment form Inside Ng-repeat -->
</div>
<!-- End of ng-repeat post in mypost -->
</div>
Main.js
$scope.addComment = function(post){
$http.post('/post/comment',{
comment_body: post.comment,
}).then(function(result){
console.log(result.data);
$scope.myposts.push(result.data);
});
};
In order to use route model binding, you have to include the post as a parameter in your route:
Route::post('post/{post}/comment', 'CommentController#create');
Then call it like this:
$http.post('/post/' + post.id + '/comment' ...
Right now in your controller you are getting an empty Post instance that has no ID.

How to insert to pivot table

I am trying to track Semi-private tennis lesson records using Laravel 5.3 and mysql. I am attempting to follow the example set in the Laravel 5 Many to Many tutorial. I have a Players model that I am trying to sync with a Sharedlessonhours table via a Player_Sharedlessonhours pivot table. In the code my sharedlessonhours table gets an inserted record, but the pivot table does not. Sorry to be so verbose, but I want to be clear about what's happening.
First the table structure.
public function up()
{
Schema::create('sharedlessonhours', function (Blueprint $table) {
$table->increments('id');
$table->date('signup_date');
$table->integer('packages_id')->unsigned();
$table->timestamps();
});
Schema::table('sharedlessonhours', function (Blueprint $table) {
$table->foreign('packages_id')->references('id')->on('packages');
});
Schema::create('player_sharedlessonhour', function (Blueprint $table)
{
$table->integer('sharedlessonhours_id')->unsigned();
$table->integer('players_id')->unsigned();
$table->timestamps();
});
Schema::table('player_sharedlessonhour', function (Blueprint $table) {
$table->foreign('sharedlessonhours_id')->references('id')->on('sharedlessonhours')->onDelete('cascade');
$table->foreign('players_id')->references('id')->on('players')->onDelete('cascade');
});
}
The create and store methods:
public function createSharedLessonhours()
{
$players = Players::orderBy('lname')->pluck('fname', 'id');
$packages = Packages::orderBy('name')->pluck('name','id');
return view('admin.lessonhours.sharedlessonhours', compact('players', 'packages'));
}
public function storeSharedLessonhours(Request $request)
{
$sharedlessonhours = SharedLessonhours::create($request->all());
$sharedlessonhours->players()->attach($request->input('players'));
}
The Form:
<div class="col-md-4 col-sm-5">
{!! Form::open(['url' => 'sharedlessonhours']) !!}
<div class="form-group">
{!! Form::label('players', 'Player(s):') !!}
{!! Form::select('players[]', $players, null, ['class' => 'form-control', 'multiple']) !!}
</div>
<div class="form-group">
{!! Form::label('signup_date', 'Signup Date:') !!}
{!! Form::text('signup_date', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('packages_id', 'Lesson Package:') !!}
{!! Form::select('packages_id', $packages, null, ['class' => 'form-control', 'placeholder' => 'Choose Package']) !!}
</div>
<div class="form-group">
{!! Form::submit('Signup', ['class' => 'btn btn-default form-control']) !!}
</div>
{!! Form::close() !!}
</div>
The screenshot of the select box for the player ids:
And screenshot for error:
I am wondering if the array is simply in the incorrect order? dd($request) shows that everything is being collected from the form and but looking at the error page seems like it is trying to insert data into the wrong fields. The line that has (3,4) wouldn't be the correct order if that matters to mysql. I tried flipping the columns in mysql, but it didn't help.
I am very confused right now.
UPDATE:
First I will share the requested code then share further steps I have taken to debug.
Players model code:
namespace App;
use Illuminate\Database\Eloquent\Model;
use Collective\Html\Eloquent\FormAccessible;
use Carbon\Carbon;
class Players extends Model
{
public $table = "players";
protected $fillable = array('fname', 'lname', 'gender', 'birthdate');
public function users()
{
return $this->belongsTo('App\User', 'users_id');
}
public function lessonHours()
{
return $this->hasMany('App\Lessonhours', 'players_id');
}
public function sharedlessonhours()
{
return $this->belongsToMany('App\SharedLessonhours', "player_sharedlessonhour","players_id", "sharedlessonhours_id" );
}
public function getFullName($id)
{
return ucfirst($this->fname ) . ' ' . ucfirst($this->lname);
}
protected $dates = ['birthdate'];
public function setBirthdateAttribute($value)
{
$this->attributes['birthdate'] = Carbon::createFromFormat('m/d/Y', $value);
}
}
SharedLessonhours:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Collective\Html\Eloquent\FormAccessible;
use Carbon\Carbon;
class SharedLessonhours extends Model
{
use FormAccessible;
protected $fillable = array('signup_date', 'packages_id');
public $table = "sharedlessonhours";
public function players()
{
return $this->belongsToMany('App\Players', "player_sharedlessonhour", "players_id", "sharedlessonhours_id");
}
public function sharedhoursused()
{
return $this->hasMany('App\SharedHoursused', 'id');
}
public function packages()
{
return $this->belongsTo('App\Packages');
}
public function setSignUpDateAttribute($value)
{
$this->attributes['signup_date'] = Carbon::createFromFormat('m/d/Y', $value);
}
}
I attempted to add a different record after changing the columns in mysql and get the error again. I switched the columns back and the error continues, eve`n after restarting tinker.
In addition to customizing the name of the joining table, you may also customize the column names of the keys on the table by passing additional arguments to the belongsToMany method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to
From laravel documentation for Many-To-Many relationship.
Accordingly the definition of players relationship in your SharedLessonhour model should be as
public function players()
{
return $this->belongsToMany('App\Players', "player_sharedlessonhour", "sharedlessonhours_id", "players_id");
}
Try changing the definition and see. I haven't tested but this seems to be the cause for constraint violation.

Laravel 5: Trouble with putting correct data on screen after combining tables

As of right now, I'm working on a Laravel-5 project and I would like to build some sort of activity log. I do have a query that combines multiple tables and gives me the data I need, but as soon as I try to put the data on screen, things go wrong.
This is the query I am using right now in me ProfileController:
$activity = DB::select("SELECT user_id, created_at, source, project_id
FROM (
SELECT id as project_id, user_id, created_at, 'project' as source FROM projects
UNION ALL SELECT project_id, user_id, created_at, 'comment' as source FROM comments
UNION ALL SELECT project_id, user_id, created_at, 'favorite' as source FROM favorites
UNION ALL SELECT project_id, user_id, created_at, 'like' as source FROM likes
) as a
WHERE user_id = $id
ORDER BY created_at DESC");
This is what the code in my profile.blade.php looks like:
<ul class="list-group">
#foreach($activity as $act)
#if($act->source == 'project')
<li class="list-group-item">{{ $act->user_id }} added a new project: {{ $act->project_id }}</li>
#elseif($act->source == 'like')
<li class="list-group-item">{{ $act->user_id }} likes {{ $act->project_id }}!</li>
#elseif($act->source == 'comment')
<li class="list-group-item">{{ $act->user_id }} commented on {{ $act->project_id }}</li>
#elseif($act->source == 'favorite')
<li class="list-group-item">{{ $act->user_id }} has {{ $act->project_id }} to his favourites!</li>
#endif
#endforeach
</ul>
And this is what my models look like:
class Project extends Model
{
protected $fillable = [
'title',
'description',
'user_id',
'snapshot',
'views'
];
public function creator() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function tags() {
return $this->belongsToMany('App\Models\Tag');
}
}
class Likes extends Model
{
protected $fillable = [
'user_id',
'project_id'
];
public function like() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function project() {
return $this->belongsTo('App\Models\Project', 'project_id', 'id');
}
}
class Comment extends Model
{
protected $fillable = [
'user_id',
'project_id',
'comment'
];
public function poster() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function project() {
return $this->belongsTo('App\Models\Project', 'project_id', 'id');
}
}
class Favorite extends Model
{
protected $fillable = [
'user_id',
'project_id'
];
public function favorite() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function project() {
return $this->belongsTo('App\Models\Project', 'project_id', 'id');
}
}
Now I do know that I am only asking to give me the user_id or project_id on my Blade page, I did this because something like $act->creator->name or $act->project->title would give me an error like:
Undefined property: stdClass::$creator
or
Undefined property: stdClass::$project
I do get that this might have to do something with the way I build my query and that mixing tables this way might have made things more difficult than they should be, but I can't seem to find a way to build this query in Eloquent or to find a way to reach the data that belong to these user_id's and project_id's without having to use the public functions I've created in my models.
With the current setup, you cannot benefit from the Laravel models, as you need to loop through different models. My recommendation is to build a new table called Activity, with 3 columns: id, type, user_id. And use Polymorphic relationship.
Also, you can benefit from Events/Listeners, in order to create the records in the Activity table. You can benefit from the Queued Listeners, so the Activity records are not created online, if this won't impact your customer experience.