Laravel 4,eloquent mysql table design issue - php

I want to be able to design a database which has the following;
customer
--------------
id(int) | name
Company
-------------------------
id(int) | name | location
queue
--------------------------------------------------------------------------------
id (datetime-primary but not auto-increment) | company_id | customer_id | position (not primary but auto-increment)
customer_queue
-----------------------
customer_id | queue_id
public function up()
{
Schema::create('queues', function(Blueprint $table)
{
$table->dateTime('id')->primary(); //dateTime for id since one is genereated every other working day
$table->integer('company_id')->unsigned();
$table->foreign('company_id')->references('id')->on('companies');
$table->integer('customer_id')->unsigned();
$table->foreign('customer_id')->references('id')->on('customers');
$table->increments('position');
$table->time('start_time');
$table->time('end_start');
$table->integer('type');
$table->time('joined_at');
$table->time('left_at');
$table->integer('customer_queue_status');
$table->timestamps();
//$table->primary(array('id', 'position'));
});
//find a way to make position auto-increment without being primary and rather set id to primary without auto-incrementing
}
I'm using laravel 4 with eloquent and it doesn't allow me to specify only primary for id in queue table and then make position auto-increment without being primary.
The error i get is as follows
>This is the error i get
>[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1068 Multiple primary ke
y defined (SQL: alter table `queues` add primary key queues_id_primary(`id`
))

Increments will automatically try to set the field as a primary key. Therefore you can not use it to increment your position automatically.
If your id field is set to primary, it is by definition unique.
I think there is no way around implementing the auto-increment on your own.
I would do it in some way like this, in your Queue model:
class Queue extends Eloquent {
//....
public static function boot() {
parent::boot();
static::creating(function($queue) {
$position = DB::table('queues')->max('position');
if(is_null($position)) $position = 0;
$position++;
$queue->position = $position;
return true;
});
}
//....
}
This way everytime you save your Queue model it should look for the highest value and increment that by one. In case you have no entry yet it will start with 1.
In your schema, set $table->integer('position')->unique();

Related

Laravel - Set data to null before deleting column from other table

I have 2 tables. (1) being users, and (2) being foods.
In the [users] table, there is a food_id bracket that is linked as a foreign key to an item/column's id in the other table [foods].
I am able to make a reservation of a [food] column, although I want to be able to press a 'confirm' button on the item once reserved, which will delete the item's targetted column in the Database.
Although since both tables are linked with a foreign key, I know that I need to set the parent key to null in order to be able to fully delete the target column. Otherwise it throws me an error that I can't delete/update a parent item with children objects.
(my food's object primary ID being linked to the authenticated user's food_id foreign key.)
This current code I tried only throws me the following error: "Call to a member function onDelete() on null"
$foodsId = User::find(auth()->user()->foods_id);
$foodsId->onDelete('set null');
$foodsId->save();
$foodDel = Foods::find($id);
$foodDel->delete();
Don't exactly know what to think here.
You could edit the foreign key constraint to do this automatically, but what you're trying to do can be done with these lines.
$food = Food::findOrFail(auth()->user()->food_id);
auth()->user()->fill(['food_id' => null])->save(); // use forceFill() if food_id is not in the User's fillable fields.
$food->delete();
To have this happen automatically, you could make a migration with the command
php artisan make:migration changeFoodIdForeignKeyConstraint --table=users
function up()
{
Schema::table('users', function (Blueprint $table) {
$table->dropForeign(['food_id']);
$table->foreign('food_id')
->references('id')->on('foods')
->onUpdate('cascade')
->onDelete('set null');
});
}
Another option is to use a model event on the Food model
class Food extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::deleting(function ($food) {
User::where('food_id', $food->id)->update(['food_id' => null]);
});
}
Actually have found my own solution. I went to directly target my first foreign key, to then asign a null parameter to it, THEN fetch the targetted ID of my item and delete its column.
$user = auth()->user();
$user->food_id = null;
$foodDel = Foods::find($id);
$foodDel->delete();

how I can add 2 auto-increment columns in the same table in the laravel database

I want to know if I can add 2 auto-increment columns in the same table in laravel? but the second has different value to start with it?
uniID I want to start from 43600000,
Schema::create('students', function (Blueprint $table){
$table->increments('id');
$table->increments('uniID');
$table->integer('student_id');
$table->timestamps();});
DB::statement("ALTER TABLE students AUTO_INCREMENT = 43600000;");
Laravel doesn't support this because databases don't generally support it. The increments() and bigIncrements() column types cannot be used multiple times in the same table Schema and will fail on create:
PDOException: SQLSTATE[HY000]: General error: 1 table "students" has more than one primary key
But if uniId will always be 43600000 larger than id, you can use a computed attribute in Eloquent:
class Student
{
public function getUniIdAttribute()
{
return $this->id + 43600000;
}
}
Then you can use this in your controllers or Blade templates:
>>> $user = Student::first()
=> App\Student{#3078
id: 1,
...
}
>>> $student->uniId
=> 43600001
The downside to this approach is that you won't be able to use uniId as a foreign key in other tables.

Setting autoincrement other than default: Laravel is not aware of the change

I wrote a migration for a table and I need the first item of the table to be fixed for default cases (i.e. id=1 is unknown).
Here's the code:
Schema::create('technicians', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('surname')->nullable();
$table->integer('str_id')->unsigned();
$table->timestamps();
$table->foreign('str_id')->references('id')->on('services');
});
\DB::statement('ALTER TABLE technicians AUTO_INCREMENT = 2;');
However, when Laravel tries to create new entries it tries to create entries using the id and using 1 to begin with. How do I tell Laravel Eloquent to start from 2? As you can see I already tried something but it seems like Eloquent tries to add the id on its own.
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY' (SQL: insert into technicians (id, name, str_id, updated_at, created_at) values (1, 'JOHN DOE', 3, 2019-03-11 13:50:00, 2019-03-11 13:50:00))
EDIT: This is the entry in the DB
public function run()
{
$default = new Technician;
$default->id = 1;
$default->name = "DESCONOCIDO";
$default->str_id = 1;
$default->save();
}
So the table has been created, unless I have misunderstood, why not just fill the first entry so it increments past 1?
For example, create a DB seed to insert data into the table for whatever record you need.
Laravel DB Seeding
Run php artisan make:seeder UsersTableSeeder
Then in the seed file:
public function run()
{
DB::table('technicians')->insert([
'name' => "John",
'surname' => "Doe",
'str_id' => 3,
etc...
]);
}
It looks like you are trying to insert a record in the DB where one already exists for the ID of 1. Check your DB.
You can set autoincrement start with this code
$table->increments('id')->start_from($yourStartValue);
add start_from and use your value for start

Set Auto Increment field start from 1000 in migration laravel 5.1

I need to start my ids from 1000 in user table, how could I create migration for this.
My current migration is:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id'); // how can I start this from 1000
$table->integer('qualification_id')->nullable();
$table->integer('experience_id')->nullable();
});
}
It should be like this(not tested).
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class MyTableMigration extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
$statement = "ALTER TABLE MY_TABLE AUTO_INCREMENT = 111111;";
DB::unprepared($statement);
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
}
}
Update
//Your migrations here:
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id')->unsigned();
$table->integer('qualification_id')->nullable();
$table->integer('experience_id')->nullable();
});
//then set autoincrement to 1000
//after creating the table
DB::update("ALTER TABLE users AUTO_INCREMENT = 1000;");
In Laravel 8 you can use from() only for MySQL / PostgreSQL:
Set the starting value of an auto-incrementing field (MySQL /
PostgreSQL)
$table->id()->from(...);
This startingValue() method also works but I didn't see this mentioned anywhere in the documentation.
$table->id()->startingValue(...);
Under the hood for mysql it uses:
public function compileAutoIncrementStartingValues(Blueprint $blueprint)
{
return collect($blueprint->autoIncrementingStartingValues())->map(function ($value, $column) use ($blueprint) {
return 'alter table '.$this->wrapTable($blueprint->getTable()).' auto_increment = '.$value;
})->all();
}
Migration to create table and set its auto-increment value as of Laravel 5.5
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->integer('qualification_id')->nullable();
$table->integer('experience_id')->nullable();
});
// Here's the magic
\DB::statement('ALTER TABLE table_name AUTO_INCREMENT = 1000;');
}
DB::statement() can be used to execute any single SQL statement you need.
Most tables work with increments incrementing from the next biggest integer.
One can always insert an integer, that is higher than the current autoincrementing index. The autoincrementing index will then automatically follow from that new value +1 up.
So, if you have a freshly minted table your current index is 0, the next key will be 0 + 1 = 1.
What we want is a primary key that starts at 1000, so what we do is insert a record with id value of 999, so the next insert will become 1000.
In code:
$startId = 1000;
DB::table('users')->insert(['id'=> $startId - 1]);
DB::table('users')->where('id',$startId - 1)->delete();
and now you have an empty table where the next insert id should be 1000.
Please note that if you have values to seed into the table with id values < startId you need to do that before you execute these statements. Otherwise the database will throw an constraint violation error.
This should work database agnostic, but if there's a database that does not follow this autoincrement rule i'd love to hear about it.
//Your migrations here:
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id')->unsigned();
$table->integer('qualification_id')->nullable();
$table->integer('experience_id')->nullable();
});
//then set autoincrement to 1000
//after creating the table
DB::update("ALTER TABLE users AUTO_INCREMENT = 1000;");
We need add Prefix table. So we need replace the line
DB::update("ALTER TABLE users AUTO_INCREMENT = 1000;");
by 2 lines below:
$prefix = DB::getTablePrefix();
DB::update("ALTER TABLE ".$prefix."users AUTO_INCREMENT = 1000;");
Prashant's method works without problems.
But as it is said earlier, don't put use DB; in the top of your file.
And here are the results after php artisan migrate

Laravel base table not found using pivot model

Hi im trying to query my tasks table. A little background information on the tables and how they are related.
Users, create Projects and Tasks, Statuses for projects and tasks can be selected from the status table, users make their own, i plan to have default ones but users may want to create their own.
By default i want to find all the users tasks where the status_name which is held in the statuses table does not equal closed. I decided it would be best to actually create a table called task_status which holds the task_id as well as the status_id. I still want to find the logged in users tasks and then find the status name based on the status_id held in the tasks table, which can be referenced in the statuses table. I then want to only display the any records not equal to closed but the first part which is explained below is trickier than first anticipated.
My table structures can be found below:
Table structure
Users
id | username | email
Tasks
id | user_id | client_id | project_id | status_id | task_name | task_brief
Statuses
id | status_name
Projects
id | user_id | client_id | status_id | type_id | project_name | project_brief
task_status
id | user_id | task_id | status_id
I'm trying to query my db simply first so that I can be sure that the data returned is correct. So I've changed my query to the below:
$user = User::with(array('tasks', 'task.status', 'tasks.taskstatus',
'tasks.clients'))->find(Auth::user()->id);
and I'm trying to return as follows (please bear in mind I also want to query the status table so that I am able to return the name of the status):
#foreach($user->tasks as $task)
{{ $task->task_name }}
#if(!is_null($task->clients))
{{ $task->clients->client_code }}
#endif
#if(!is_null($task->taskstatus))
{{ $task->taskstatus->status_name }}
#endif
#endforeach
My models:
Task.php
public function status(){
return $this->hasOne('Status', 'status_id');
}
public function taskstatus() {
return $this->hasMany('TaskStatus', 'status_id');
}
Status.php
public function tasks()
{
return $this->hasMany('Task');
}
public function taskstatus()
{
return $this->hasMany('TaskStatus', 'status_id');
}
TaskStatus.php
public function tasks()
{
return $this->hasMany('Task', 'task_id');
}
public function status() {
return $this->belongsTo('Status', 'status_id')
}
However using the above returns the following error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'imanage.task_statuses' doesn't exist (SQL: select * from `task_statuses`
where `task_statuses`.`status_id` in (?, ?, ?, ?, ?, ?, ?))
(Bindings: array ( 0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6, 6 => 7, ))
I'm sure that its my relationships that are defined incorrectly but I am not sure how to correct these.Can anyone help?
You can also try this code:
$user = User::whereHas('task.status', function($q)
{
$q->where('status', '!=', 'close');
})
->with('task', 'task.clients')
->where('id', Auth::user()->id)
->first();
Check the eloquent docs on querying relationships.
also remember DO NOT ECHO VIEW, return the view instead.
The error seems related to the fact that Laravel (well, actually Eloquent) is getting the wrong table name: below you have task_statuses instead of task_status. Remember that Eloquent will attempt to pluralize named models to get the table name.
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'imanage.task_statuses' doesn't exist
So either rename your table to match Laravel expectations, or in your model specify a custom table name:
class TaskStatus extends Eloquent {
protected $table = 'task_status';
...
Additionally, this part of your code is unclear to me:
Task.php
public function status(){
return $this->hasOne('Status', 'status_id');
}
public function taskstatus() {
return $this->hasMany('TaskStatus', 'status_id');
}
Does your Task have one status, or does it have many statuses?

Categories