Using: Laravel 5.5
I Constructing addresses using some address elements (like: district, area, zip etc) as dropdowns & also some user inputs.
I have 5 address element & one of their schema is:
Schema::create('address_districts', function (Blueprint $table) {
$table->increments('id');
$table->integer('admin_id')->unsigned();
$table->string('name');
$table->timestamps();
$table->foreign('admin_id')->references('id')->on('admins');
});
This is for Districts, & I have another 3 exactly same like this called, address_thanas, address_areas, address_building_names & address_zips;
The only exception for the last one is that has code instead of name on other tables:
Schema::create('address_zips', function (Blueprint $table) {
$table->increments('id');
$table->integer('admin_id')->unsigned();
$table->string('code'); // Look other table has name here........
$table->timestamps();
$table->foreign('admin_id')->references('id')->on('admins');
});
I store constructed addresses on the table called addresses
Schema::create('addresses', function (Blueprint $table) {
$table->increments('id');
$table->integer('district_id')->unsigned();
$table->integer('thana_id')->unsigned();
$table->integer('area_id')->unsigned();
$table->integer('zip_id')->unsigned();
$table->integer('building_name_id')->nullable()->unsigned();
$table->string('building');
$table->integer('floor');
$table->string('apt')->nullable();
$table->text('comment')->nullable();
$table->timestamps();
$table->foreign('district_id')->references('id')->on('address_districts');
$table->foreign('thana_id')->references('id')->on('address_thanas');
$table->foreign('area_id')->references('id')->on('address_areas');
$table->foreign('zip_id')->references('id')->on('address_zips');
$table->foreign('building_name_id')->references('id')->on('address_building_names');
});
In Address Model I've defined relationships like:
public function district() {
return $this->belongsTo(AddressDistrict::class, 'district_id');
}
public function thana() {
return $this->belongsTo(AddressThana::class, 'thana_id');
}
public function area() {
return $this->belongsTo(AddressArea::class, 'area_id');
}
public function building_name() {
return $this->belongsTo(AddressBuildingName::class, 'building_name_id');
}
public function zip() {
return $this->belongsTo(AddressZip::class, 'zip_id', 'id');
}
Then when I try to create a new address using Address::create($data)
I get error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'name' in 'where clause' (SQL: select count(*) as aggregate from `address_zips` where `name` = 2)
Here we can see that it is comparing the key name instead of id
I noticed that this is not reporting that the data cannot be inserted or something like that, it fails to count related model & for that aborts insertion of data
Why is that?
But the strange thing is I can retrieve data by (inserted a row manually into db for testing to see if that can retrieve data)
$addresses = Address::orderByDesc('created_at')->get();
//loop as $address
$address->district->name
$address->zip->code
...
& this works perfect
When I am creating a new record I need that query look like:
select count(*) as aggregate from `address_zips` where `id` = 2
Any help will be highly appreciated.
Thanks for reading this long question.
The problem is in your $data array. Probably you copied a form with an input name, you need to rename it to code in order to save the values automatically.
Alternatively, you can set the input manually
$address = new Address();
$address->code = request('name');
$address->save();
Related
I have a table with 3 columns:
firstname
lastname
fullname
in migration:
Schema::create('owners', function (Blueprint $table) {
$table->id();
$table->string('firstname',20);
$table->string('lastname', 20);
$table->string('fullname')->storedAs('CONCAT(firstname,lastname)');
$table->timestamps();
});
the problem is that i want to change the concatenation order in the controller i tried to use db statement but it doesn't work
-in the controller:
$owners= Owner::findOrFail($id);
$owners->update([
'firstname'=>$request['firstname'],
'lastname' =>$request['lastname'],
]);
DB::statement('UPDATE owners SET fullname AS CONCAT(lastname,firstname) STORED WHERE ID=1 ');
I don't want to just use a simple concatenation because the user can change the firstname or the lastname and the order that's why I used storedAs()
any ideas please?
The storedAs method in the migration creates a generated column in mysql. The value is automatically generated from the column values of the firstname and the lastname. There's no way you can change this via an UPDATE statement. You'd have to use an ALTER TABLE statement, which would be horrifically bad practice.
If I were you, I'd keep full name display as a model method so you could access it by using $owner->fullNameFirstLast() or $owner->fullNameLastFirst()
What you should do is create a new migration in order to change the column, the code would be something like this:
Schema::table('owners', function (Blueprint $table) {
$table->string('fullname')->storedAs('CONCAT(lastname,firstname)');
});
This way the column will be changed on a database level, and no need for the controller query you have added
Simply try this
1- update your migration to
Schema::create('owners', function (Blueprint $table) {
$table->id();
$table->string('firstname',20);
$table->string('lastname', 20);
$table->string('fullname', 56);
$table->timestamps();
});
2- in your controller
$owners= Owner::findOrFail($id);
$first_name = $request->firstname ?? $owners->firstname;
$last_name = $request->lastname ?? $owners->lastname;
$full_name = $first_name.' '.$last_name;
$owners->update([
'firstname'=>$first_name,
'lastname' =>$last_name,
'fullname' =>$full_name,
]);
You can also write it this way
DB::statement(DB::raw("UPDATE owners SET firstname = '".$first_name."', lastname = '".$last_name."', fullname = '".$full_name."' WHERE id = $id"));
And the same way for your Create function as well
I'm trying to edit a column of datatable to show informations in my index view table.
This is my controller's method that I call throught Ajax in the view:
public function getField(){
// Current User
$user_id = \Auth::user()->id;
$users = User::find($user_id)->users();
return Datatables::of($users )
->editColumn('id', 'Edit')
->editColumn('fields_id', function($users) {
$mystring = '';
$fields_id_array = json_decode($users->fields_id);
foreach($fields_id_array as $f_id){
/* this works */
// $mystring .= Fields::where('id', '=', $f_id) -> pluck('field_name');
/* this doesn't work */
$mystring .= Fields::find($f_id) -> pluck('field_name');
}
return $mystring;
})
->rawColumns(['id'])
->make(true);
}
The field 'fields_id' in users table is a JSON field like this: ['1','2','5'] and these refers to the id's of another table: 'Fields'.
I have already read this questions but I think my db table is it ok because increments are primary-key equivalent in Laravel migrations.
This is my migration for the table 'fields':
public function up()
{
Schema::defaultStringLength(191);
Schema::create('fields', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->string('code')->unique();
$table->string('param1');
$table->string('param3')->nullable();
$table->timestamps();
});
}
Thanks
a wild guess here, based on your last comment...
try this inside you loop
$mystring .= Fields::find(intval($f_id))->pluck('field_name');
I've added the intval() function arround your $f_id since you said you said they are in this format ['1','2','5']. that is an array of strings (that should be cast to integers if you plan to use them with find() function.
I have this table :
public function up()
{
Schema::create('edition', function (Blueprint $table) {
$table->increments('id');
$table->integer('volume');
$table->text('cover')->nullable();
$table->enum('number', ['1', '2']);
$table->timestamps();
});
Schema::table('journal', function(Blueprint $table) {
$table->foreign('id_edition')->references('id')->on('edition')->onDelete('cascade')->onUpdate('cascade');
});
}
I wanted to make the combination of column Volume and Number as a unique key. For example, there is a data "Volume 1, Number 1" and when user insert the same combination it will throw an error message that the data already exist. Is there a way I can do this in Laravel ?
Just include the following snippet inside the up() method
$table->unique(['volume','number']);
By having this constraint set, if you insert 'Volume 1 , Number 1` once it'll be fine. However, if you try to do the same again, it'll throw an error.
Conditions:
You are using some good DBMS, such as MySQL and not SQLITE
You successfully migrated this change into the database.
You can also use uniquewith-validator package that allows you to validate a unique combination of fields like this
'field1' => 'required|unique_with:table_name,field2'
The above code will check if the combination of field1 and field2 is unique in the table with the given table_name.
I am having the said problem when defining one to many relationship with two models, the Student and Enrollment. When accessing the table from another table using:
$enrollment = App\Enrollment::first();
$enrollment->students()->first_name;
Im getting :
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'students.enrollment_id' in 'where clause' (SQL: select * from `students` where `students`.`enrollment_id` = 1 and `students`.`enrollment_id` is not null)'
However when I use :
$enrollment = App\Enrollment::first();
$enrollment->students()->first_name;
Im getting :
PHP error: Undefined property: Illuminate\Database\Eloquent\Relations\HasMany::$first_name on line 1
Can someone help me on this?
Enrollment
protected $fillable = [
'subject_code',
'subject_description',
'section',
'schedule',
'room_no',
'no_of_units'
];
public function students()
{
return $this->hasMany('App\Student');
}
Student
protected $fillable = [
'enrollments_id',
'student_no',
'first_name',
'last_name',
'middle_name',
'birthdate',
'fathers_name',
'mothers_name',
'phone_no',
'degree_id',
'city_id',
'address'
];
public function enrollment()
{
return $this->belongsTo('App\Enrollment');
}
Here's the table for the students and enrollment accordingly
Schema::create('students', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->integer('enrollments_id')->unsigned();
$table->integer('student_no');
$table->foreign('enrollments_id')->references('id')->on('enrollments')->unsigned();
$table->string('first_name');
$table->string('last_name');
$table->string('middle_name');
$table->date('birthdate');
$table->string('fathers_name');
$table->string('mothers_name');
$table->string('phone_no');
$table->string('address');
$table->integer('city_id');
$table->integer('degree_id');
$table->timestamps();
});
Schema::create('enrollments', function (Blueprint $table) {
$table->increments('id');
$table->string('subject_description');
$table->string('subject_code');
$table->time('schedule');
$table->string('room_no');
$table->integer('no_of_units');
$table->string('section');
$table->timestamps();
});
First of all what you exactly want
as per your question i am assuming you want 'enrollment has many students', for this relationship you need enrolment_id in students table not student_id in enrollment table.
and after that use
$students= Enrolment::find(id)->students;
it will return all students with the required enrollment id
That normal since you're trying to get property first_name from hasMany object, you should use get() method if you want to get Collection of objects (in your case collection of students) :
$enrollment->students()->get();
And if you want to get the first name you should specify the object you want to get the first_name from it, e.g :
$enrollment->students()->first()->first_name;
$enrollment->students()->last()->first_name;
If you want to get the attribute first_name of all the students you should use lists method, e.g :
$enrollment->students()->lists('first_name');
Output: collection of all students first names.
Hope this helps.
Update :
Try to remove ->unsigned() in :
$table->increments('id')->unsigned();
and also in :
$table->foreign('enrollments_id')->references('id')->on('enrollments')->unsigned();
When you call relations on an eloquent object it actually return you the relation not the exact objects
for eg: in your case
$enrollment->students() will return the relation
where as
$enrollment->students will return the eloquent object ( in belongs to, has one relations ) and collection/array of eloquent object/objects(in one to many , many to many relations )
simply if you are using it as an attribute you will get the actual result and relation query if it is called as a function
even if you get the relation you can get the results by calling get on top of that
$enrollment->students()->get()
I'm trying to assign big integers in my columns but it won't allow me to define the relationship unless I change it to standard integer. No biggy, but would be interested to know why this throws up migration errors for me.
MIGRATION (working)
public function up()
{
//create the table
Schema::create(self::TBL_eportfoliouservalues, function($table){
$table->engine = 'InnoDB';
$table->increments('id');
$table->integer('user')->unsigned()->index();
$table->integer('document')->unsigned()->index();
$table->integer('section')->unsigned()->index();
$table->integer('element')->unsigned()->index();
$table->integer('parent');
$table->text('value');
// foreign indexes
$table->foreign('user')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('document')->references('id')->on('eportfoliodocuments')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('section')->references('id')->on('eportfoliosections')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('element')->references('id')->on('eportfolioformelements')->onDelete('cascade')->onUpdate('cascade');
});
}
MIGRATION (not working)
public function up()
{
//create the table
Schema::create(self::TBL_eportfoliouservalues, function($table){
$table->engine = 'InnoDB';
$table->increments('id');
$table->bigInteger('user')->unsigned()->index();
$table->bigInteger('document')->unsigned()->index();
$table->bigInteger('section')->unsigned()->index();
$table->bigInteger('element')->unsigned()->index();
$table->bigInteger('parent');
$table->text('value');
// foreign indexes
$table->foreign('user')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('document')->references('id')->on('eportfoliodocuments')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('section')->references('id')->on('eportfoliosections')->onDelete('cascade')->onUpdate('cascade');
$table->foreign('element')->references('id')->on('eportfolioformelements')->onDelete('cascade')->onUpdate('cascade');
});
}
ERROR
[Exception]
SQLSTATE[HY000]: General error: 1005 Can't create table 'drillers.#sql-1a4_2c2' (errno: 150) (SQL:
alter table `eportfoliouservalues` add constraint eportfoliouservalues_user_foreign foreign key (
`user`) references `users` (`id`) on delete cascade on update cascade) (Bindings: array (
))
How are the IDs defined on the other tables? If you use $table->increments('id') then that will create columns of the type integer, and as the foreign key field has to match the primary key field on the other table, you won't be able to create a relationship.
The way to get around this would be to use $table->bigIncrements('id') on the other tables.
If primary key in tableOne migration (by default it is ) is BigInteger
So the foreign key in tableTwo migration should be bigInteger with unsigned() function.
Codes for example.
Migration for tableOne
public function up()
{
Schema::create('tableOne', function (Blueprint $table) {
$table->bigIncrements('id');
}
Migration for tableTwo
public function up()
{
Schema::create('tableTwo', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('fk_id')->unsigned()->nullable() ;
$table->bigInteger('fk_id')->default(20)->change();
$table->foreign('fk_id')->references('id')->on('tableOne');
}
Hope this helps someone.
This is late to the party but I thought should be shared somewhere.
This was a perfectly valid upgrade that was not so well documented. The type needs to match for ids and foreign keys.
This script outputs the migration you need.
Use at your own risk having BACKED UP YOUR DATABASE. Make a migration and add the following to up(). Leave down() empty so you can rollback and tweak as needed. It will not actually do anything but will output what needs to be done. You can then paste the output into your migration file once you are happy with what you see.
If you uncomment the echos you can see what was looked at and determined needs changing.
$tableName = $table->Tables_in_yourdatabasename; //eg Tables_in_myproject
Modify the above line in the code below
$tables = \DB::select('SHOW TABLES');
// this just to get the tabs right in sublime;
$i = 0;
foreach($tables as $table) {
// ### Change yourdatabasename below ###
$tableName = $table->Tables_in_yourdatabasename;
// echo "#######################\n";
// echo '########## '.$tableName."##########\n\n";
$columns = \DB::select('show columns from ' . $tableName);
foreach ($columns as $value) {
if((substr($value->Field, -2) === 'id') && (substr($value->Type,0,3) === "int" || substr($value->Type,0,6) === "bigint")) {
// echo "$value->Field : type is '$value->Type'\n" ;
if(substr($value->Type,0,6) === "bigint") {
// echo "No Change needed\n";
}
if(substr($value->Type,0,3) === "int") {
// echo "To Update $value->Field to 'BIGINT':\n\n";
if($i === 0) {
echo 'Schema::table(\''.$tableName.'\', function (Blueprint $table) {'."\n";
$i++; //only matters for the first row. For the tabs.
}else{
echo "\t\t".'Schema::table(\''.$tableName.'\', function (Blueprint $table) {'."\n";
}
// maintain the auto increment
if($value->Field === 'id') {
echo "\t\t".' $table->bigIncrements(\'id\')->change();'."\n\t\t";
}else{
echo "\t\t".' $table->bigInteger(\''.$value->Field.'\')->unsigned()->change();'."\n\t\t";
}
echo '});'."\n";
}
}
}
// echo "\n\n";
}
Be careful and examine the output carefully as you may not want to change all the tables. I would skip the migrations table for example as I doubt you will reference it.
In case I didn't say it. BACK UP YOUR DATABASE FIRST. Good Luck