first time working with Laravel and PHP. I am trying to insert row in the table profile where the attribute uID is a foreign key referencing to uID on user table, but getting errors. How do I insert just the summary attribute of the profile and set the uID (foreign key) automatically. I can insert users with uID without any problems. Here are my model and controller files. Thanks!
user model
namespace App;
use Illuminate\Database\Eloquent\Model;
class user extends Model
{
// specify which attributes can be filled out during registration
public $timestamps = false;
protected $fillable=['firstname','lastname','email','password',];
public function profile(){
return $this->hasOne(profile::class);
}
}
profile model
namespace App;
use Illuminate\Database\Eloquent\Model;
class profile extends Model
{
//
public $timestamps = false;
protected $fillable = ['summary',];
public function user(){
return $this->belongsTo(user::class);
}
}
profile migration
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProfilesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
// create profile table
Schema::create('profiles', function (Blueprint $table) {
$table->increments('pID');
$table->timestamp('created_at')->useCurrent();
$table->string('summary')->default('');
$table->unsignedInteger('uID');
$table->foreign('uID')->references('uID')->on('users')->onDelete('cascade');
});
}
}
profile controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\profile;
class ProfileController extends Controller
{
public function create()
{
//
return view('profile.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
// used to store user profile after validation
$this->validate($request,[
'summary' => 'required'
]);
$profile = new profile([
'summary' => $request->get('summary'),
'uID' => $request->user()->uID
]);
return redirect()->route('profile.create')->with('success','Profile created');
}
}
Welcome to Laravel :)
On your profile Model on the user method you need to define the foreign key.
public function user(){
return $this->belongsTo(user::class, 'uID');
}
If you don't provide the foreign key, it will look for user_id field.
Alright, a couple of things that could need to be sort out:
Declare your Classes with a capitalised letter. It is Profile not profile. Avoid plurals as well. More on that can be explored reading about PSR-x;
You have deviated from the laravel way in regards to foreign keys. Therefore, you need to specify in your relationship which are the keys to connect with:
Also, notice how I changed your method name from user -> users
public function users()
{
return $this->belongsTo(user::class, 'id', 'uID');
}
As well as for your profile relationship:
public function profiles(){
return $this->hasOne(profile::class, 'uID', 'id');
}
hi put your database here and add forign key to the model
Related
I'm try to use Laravel 8.x and Laravel sanctum 2.14.2 to authenticate my API and UUIDs as the primary key for my User model.
My custom PersonalAccessToken model
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
class PersonalAccessToken extends SanctumPersonalAccessToken
{
use HasFactory;
protected $table = 'personal_access_tokens';
public function tokenable()
{
return $this->morphTo('tokenable', "tokenable_type", "tokenable_id", "uuid");
}
}
My personal_access_tokens migration schema
...
public function up()
{
Schema::dropIfExists('personal_access_tokens');
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->uuidMorphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamps();
});
}
...
My AppServiceProvider
...
use App\Models\PersonalAccessToken;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
Sanctum::ignoreMigrations();
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
if($this->app->environment('production')) {
URL::forceScheme('https');
}
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}
}
When I try to get the token with $user->createToken($user->email)->plainTextToken, I get this error:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'tokenable_id' cannot be null (SQL: insert into `personal_access_tokens` (`name`, `token`, `abilities`, `tokenable_id`, `tokenable_type`, `updated_at`, `created_at`) values (admin#gmail.com, 85dbe44c32a999a01f4a97d9c9eab0710125a6ac5f861ab546a5822f61015b23, [\"*\"], ?, App\\Models\\User, 2022-03-20 19:16:43, 2022-03-20 19:16:43))
I think the cause of the error is that I am using uuid as the primary key in the users table
Schema::create('users', function (Blueprint $table) {
$table->uuid('uuid')->primary();
...
});
UPDATE
My User Model
...
class User extends Authenticatable
{
use HasUUID;
use HasApiTokens;
use HasFactory;
use Notifiable;
use HasRoles;
...
public function tokens()
{
return $this->morphMany(Sanctum::$personalAccessTokenModel, 'tokenable', "tokenable_type", "tokenable_id");
}
...
}
Any help would be appreciated.
Is there any particular reason for you to create custom PersonalAccessToken model?
If it's just UUID that you want for the primary key of your User model, you can achieve it without creating the custom PersonalAccessToken model.
Your personal_access_tokens migration schema seems fine.
I think the cause of the error is that I am using uuid as the primary
key in the users table
Schema::create('users', function (Blueprint $table) {
$table->uuid('uuid')->primary();
...
});
This could be the issue. Try changing the column name to just id from uuid and see if it works
$table->uuid('id')->primary();
If you must use the column name as uuid for primary key, then try adding the following to your User model
protected $primaryKey='uuid'
By default eloquent assumes the name of the primary key column as 'id'. This will let eloquent know to look for 'uuid' as primary key column for User model.
Also since you are not using the default integer data type for primary key make sure you have the following in your User model
public $incrementing=false
protected $keyType='string'
You can refer to Laravel Documentation for
Primary Keys
Sorry for late reply. I answer with the solution for anyone who is having the same problem as above.
The problem is in my UUId Traits. We should use boot magic method as Laravel suggested when we want to create our own Traits.
Solution:
Using App\Traits\HasUUID with the correct code
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
trait HasUUID
{
/**
* Boot functions from Laravel.
*/
// protected static function boot() <- This line is INCORRECT
protected static function bootHasUUID()
{
static::creating(function (Model $model) {
$model->primaryKey = 'uuid';
$model->keyType = 'string'; // In Laravel 6.0+ make sure to also set $keyType
$model->incrementing = false;
if (empty($model->{$model->getKeyName()})) {
$model->{$model->getKeyName()} = Str::uuid()->toString();
}
});
}
/**
* Get the value indicating whether the IDs are incrementing.
*
* #return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Get the auto-incrementing key type.
*
* #return string
*/
public function getKeyType()
{
return 'string';
}
}
And finally, add the App\Traits\HasUUID in User Model.
...
use App\Traits\HasUUID;
...
class User extends Authenticatable
{
use HasUUID;
...
}
No need to customize Sanctum's Model. Thank you so much #Hussain, #Dharman
Backround information
Using Laravel I'm building an application where I want to link a Company profile to a Station.
Company.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
protected $guarded = [];
protected $table = 'companies';
public function user()
{
return $this->hasMany('App\User');
}
public function station()
{
return $this->belongsToMany('App\Station')->withPivot('company_stations');
}
public function line()
{
return $this->belongsToMany('App\Line');
}
}
Station.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Station extends Model
{
protected $guarded = [];
protected $table = 'stations';
public function lines()
{
return $this->belongsToMany('App\Line');
}
public function company()
{
return $this->belongsToMany('App\Company')->withPivot('company_stations');
}
}
company_stations migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCompanyStationsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('company_stations', function (Blueprint $table) {
$table->id();
$table->integer('company_id')->unsigned();
$table->integer('station_id')->unsigned();
$table->boolean('following')->default(false);
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('company_stations');
}
}
I also have a migration company_stations, but no Model for it.
The question
I want to create a checkbox on the station view where the currently logged in Company ID is linked to the Station ID in the pivot table to keep track of which stations the company is following and wether the company has completed that station or not.
What would be the easiest and most clean approach to this? Do I make a new Model CompanyStation + controller or can this be filled in from the Company or Station controller?
You can use sync method of belongsTomany relationship.
$station = Station::find($stationid);
$station->company()->sync([1,2,3]); //1,2,3 is the company ids which you're selection through checkbox.
//this will drop all the existing companies except the companies with id 1,2,3. If these ids don't exist it will attach them (still dropping the existing ones).
if you add a column to your piviot table company_stations example: 'completed' you can access it with
foreach ($company->stations as $station) {
dd($station->pivot->completed);
}
you can add that data via
$company->stations()->attach($station->id, ['completed' => true]);
Query it
//only show me completed company stations. (from piviot)
Company::whereHas('stations', function($q) {
$q->where('company_stations.completed', true);
})
->get();
I have a problem with creating pivot table in Laravel. That's the first time I'm using it, and after searching on Internet, I can't manage to fix my issue.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'champions_teams.teams_id' in 'field list' (SQL: select `champions`.*, `champions_teams`.`teams_id` as `pivot_teams_id`, `champions_teams`.`champions_id` as `pivot_champions_id`, `champions_teams`.`champion_id` as `pivot_champion_id` from `champions` inner join `champions_teams` on `champions`.`id` = `champions_teams`.`champions_id` where `champions_teams`.`teams_id` = 1) (View: C:\laragon\www\proyecto-web\resources\views\teams\teamIndex.blade.php)
Following, the way I created my classes "Champions" and "Teams", with my pivot table migration.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\softDeletes;
class Teams extends Model
{
use SoftDeletes;
protected $table = 'teams';
protected $fillable = ['user_id','name','rank','region'];
public function user(){
return $this->belongsTo(User::class);
}
public function champions(){
return $this->belongsToMany(Champions::class)->withPivot('champion_id');
}
public function files(){
return $this->morphMany(File::class, 'model');
}
public function setNameAttribute($value){
$this->attributes['name'] = strtoupper($value);
}
public function getTeamsNameAttribute(){
return $this->name;
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Champions extends Model
{
protected $table = 'champions';
protected $fillable = ['name','health_points','type','role'];
public function teams(){
return $this->belongsToMany(Teams::class)->withPivot('team_id');;
}
public function items(){
return $this->hasMany(Items::class, 'champion_id');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class PivotTables extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('champions_teams', function(Blueprint $table){
$table->unsignedBigInteger('champion_id');
$table->unsignedBigInteger('team_id');
$table->foreign('champion_id')
->references('id')
->on('champions')
->onDelete('cascade');
$table->foreign('team_id')
->references('id')
->on('teams')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
//
}
}
Thanks for your help ! You can also access the whole code right here : https://github.com/ValentinDelpy/proyecto-web
Many to Many
Since you are not following the name conventions which Laravel expects, you should customize the name of the joining table, 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:
class Champions extends Model
{
public function teams(){
return $this->belongsToMany(Teams::class, 'champions_teams', 'team_id', 'champion_id');
}
}
class Teams extends Model
{
public function champions(){
return $this->belongsToMany(Champions::class, 'champions_teams', 'champion_id', 'team_id');
}
}
Seems You have collision with teams and team.
You model is named Teams (should be Team).
Checkout how to make many to many relations propely:
Laravel docs
Probably Laravel is generating the id from the Model name, so if the Project is brand new, just change it, otherwise, you have to declare the foreign keys name in the belogsToMany function (check https://laravel.com/api/6.x/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_belongsToMany).
Also keep in mind that the witPivot function is to let Laravel know the existence of other fields more than the only 2 foreign keys, not the foreign keys themself (check https://laravel.com/api/6.x/Illuminate/Database/Eloquent/Relations/BelongsToMany.html#method_withPivot)
I'm new to Laravel & Eloquent, I'm coming from Django.
In Django I can create a filter on my results and use an object to filter the results...
I'm trying to figure out if I could do this in Laravel/Eloquent also...
Here's what I'm trying to do....
create_messages_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMessagesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('messages', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('user_id');
$table->string('message');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('messages');
}
}
Message.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
MessageController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Message;
use Illuminate\Support\Facades\Auth;
class MessageController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$messages = Message::where("user", Auth::user())->get();
dd($messages);
return $messages;
}
}
The problem is that when the controller index() function is routed too... I get an error saying "user" column does not exist... and it doesn't but I assumed the models user() function would take care of that and that I would be able to compare it's returning object with Auth::user().
Am I wrong, or am I just doing it wrong?
In the "where" query, the first parameter must be a column in the database. If you want to make use of a "user" column, I'll suggest you add a user column to your table.
I think the auth:user() is to authenticate the current user.
So laravel eloquent is only alerting you that the "user" column does not exist. I will suggest you create a user column, and see what happens next.
I'm currently working on a delete function for my roles.
Every time when I try to delete:
Class name must be a valid object or a string
How do I fix this?
Add this function into Role.php model
<?php
namespace App;
use Illuminate\Support\Facades\Config;
public function users()
{
return $this->belongsToMany(
Config::get('auth.providers.users.model'),
Config::get('entrust.role_user_table'),
Config::get('entrust.role_foreign_key'),
Config::get('entrust.user_foreign_key'));
}
}
Hope this helps!
Update the config/auth.php file with 'model' => App\Users::class , because vendor/zizaco/entrust/src/Entrust/Traits/EntrustRoleTrait.php point to Config::get('auth.model') in the $this->belongsToMany() method.
#Tiến Đạo says the best way to solve this problem. But If you want code simplicity....
use App\User;
class Role extends EntrustRole
{
/**
* Many-to-Many relations with the user model.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users()
{
return $this->belongsToMany(User::class);
}
}