I am trying to save multiple data which is having a many-to-many relationship. My store method is like the below.
public function store(Specification $specification, Fraction $fraction, Request $request)
{
$data = return request()->validate([
'specification_no' => 'required|string',
'grade' => 'required|integer',
'gname' => 'required|integer',
'gsize' => 'required|integer',
'fractions.*.fraction_min' => 'required',
'fractions.*.fraction_max' => 'required',
'fractions.*.unit_id' => 'required',
'fraction_sieves.*.sieve_id' => 'required',
'params.*.para_min' => 'required',
'params.*.para_max' => 'required',
'units.*.unit_id' => 'required',
]);
// Save specificatio without duplicates.
$specification = new Specification($this->specificationValidation());
$checkSpecification = Specification::where('specification_no', request()->specification_no)->first();
if (!$checkSpecification) {
$specification->save();
$specification->grades()->syncWithoutDetaching($data['grade']);
$specification->gnames()->syncWithoutDetaching($data['gname']);
$specification->gsizes()->syncWithoutDetaching($data['gsize']);
$specification->sieves()->syncWithoutDetaching($data['fraction_sieves']);
// $specification->load('sieves.fractions');
$fraction = $specification->sieves()->fractions()->createMany($data['fractions']);
dd($fraction);
}
return redirect()->back()->with('alert', 'Duplicate Specification number.');
}
Models & migrations like below.
Fraction-Model
class Fraction extends Model{
protected $guarded = [];
public function sieves()
{
return $this->belongsToMany(Sieve::class);
}
}
migration - fraction
public function up(){
Schema::create('fractions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->double('fraction_min');
$table->double('fraction_max');
$table->unsignedBigInteger('unit_id');
$table->timestamps();
});
}
model - sieve
class Sieve extends Model{
protected $guarded = [];
public function specifications(){
return $this->belongsToMany(Specification::class);
}
public function fractions(){
return $this->belongsToMany(Fraction::class);
}
}
migration pivot table - fraction_sieve
public function up()
{
Schema::create('fraction_sieve', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('sieve_id');
$table->unsignedBigInteger('fraction_id');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('fraction_sieve');
}
When I use the below code
$fraction = $specification->sieves()->fractions()->createMany($data['fractions']);
to save fractions to fractions table with distance relationships from specifications->sieves->fractions, I am getting errors like this.
BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsToMany::fractions()
Normally this could be the way of creating new multiple data into db. But I can not understand why I'm getting errors. Can someone explain what I've messed up?
This is the wrong way you are trying to use: ->sieves()->fractions()
because the Sieve and Fraction model have many to many relationship so firstly you need to specify which sieves you want to create fractions for:
->sieves()->first()->fractions()->....
or
->sieves()->find(3)->fractions()->....
Related
I use laravel 8 :
public function up()
{
Schema::create('user', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->integer('created_by')->nullable();
$table->string('created_by_user')->nullable();
$table->timestamps();
});
}
Models:
<?php
namespace App\Models\Backend\MySQL;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'user';
}
In controller :
use App\Models\User;
public function store(Request $request) {
$data = [
'name' => !empty($request->name) ? $request->name : 'Jony',
'created_by' => auth()->user()->id,
'created_by_user' => auth()->user()->name,
];
User::insert($data);
}
I have successfully inserted. But the problem is that my created_by and updated_by columns are not updating automatically. Is there any way to solve this problem. In the user model I also don't set protected $timestamps = false but it doesn't work. Thank you.
insert method is not for eloquent models and doesn't update created_at and updated_at.
you should use create method instead.
create method sets created_at and updated_at automatically
see this answer here
https://stackoverflow.com/a/58075757/7689224
You should use create instead of insert.
User::create($data);
Use create() method instead of insert()
public function store(Request $request) {
$data = [
'name' => !empty($request->name) ? $request->name : 'Jony',
'created_by' => auth()->user()->id,
'created_by_user' => auth()->user()->name,
];
User::create($data);
}
I want the contacts to be displayed specifically according to the group. The groups in turn are being displayed according to the logged in user. However, all the contacts for the user are being displayed in every group that the user creates.It works when the value is being hardcoded but I want the value to be assigned dynamically.How do I do that?
This is the group controller
class GroupController extends Controller {
public function index()
{
$groups = Group::where('user_id',Auth::user()->id)->get();
return view('groups.index', compact('groups'));
}
public function store(Request $request)
{
$group = $request->all();
$request->validate([
'group_name'=>'required',
]);
$group = new Group([
'group_name' => $request->get('group_name'),
'user_id' => Auth::user()->id,
]);
$group->save();
return redirect('/groups');
}}
This is the contact controller
class ContactController extends Controller{
public function index(Request $request)
{
$group_id=$request->query('id');
$contacts = Contact::where('user_id',Auth::user()->id)->where('group_id','=','id')->get();
return view('contacts.index', compact('contacts'));
}
public function store(Request $request)
{
$contact = $request->all();
$request->validate([
'contact_name'=>'required',
'contact_number'=> 'required|integer',
'contact_email' => 'required'
]);
$contact = new Contact([
'contact_name' => $request->get('contact_name'),
'contact_number'=> $request->get('contact_number'),
'contact_email'=> $request->get('contact_email'),
'user_id' => Auth::user()->id,
'group_id'=> $request->query('id'),
]);
$contact->save();
return redirect('/contacts');
}}
This is the migration for contacts.
class CreateContactsTable extends Migration{
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('group_id')->unsigned();
$table->string('contact_name');
//$table->string('contact_number');
$table->string('contact_email');
$table->string('contact_number')->nullable();
$table->timestamps();
});
Schema::table('contacts', function($table) {
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('group_id')->references('id')->on('groups');
});}
I just read more documentation and issues for this problem to resolve that , but nothing work for me, i have 2 table wit this models:
class Month extends Model
{
protected $guarded = ['id'];
public function lessons()
{
return $this->hasMany(Lesson::class);
}
}
class Lesson extends Model
{
protected $guarded = ['id'];
public function months()
{
return $this->belongsTo(Month::class);
}
}
I can save some data with relation ship with this sample code and that work fine:
$month = Month::find(1);
$lesson = new Lesson();
$lesson->title = $request->title;
$lesson->content = $request->content;
$lesson->file_url = $uploadedFilePath;
$lesson->filename = $filename;
$lesson->time = $request->time;
$month = $month->lessons()->save($lesson);
now I try to update some lesson fields with this code:
$lesson = Lesson::find($id);
$lesson->update([
'title' => $request->title,
'content' => $request->content,
'file_url' => $uploadedFilePath,
'filename' => $filename,
'time' => $request->time
]);
$month = Month::find($request->months['0']);
$lesson = Lesson::find($lesson->id);
$lesson->months()->associate($month)->save();
in that I try to change month_id column on Lesson table in database with for example $month->id value, how can I do that?
UPDATED:
class Lesson extends Model
{
protected $guarded = ['id'];
public function month()
{
return $this->belongsTo(Month::class);
}
}
Controller:
$lesson->update([
'title' => $request->title,
'content' => $request->content,
'file_url' => $uploadedFilePath,
'filename' => $filename,
'time' => $request->time
]);
$month = Month::find($request->months['0']);
$lesson = Lesson::find($lesson->id);
$lesson->month()->associate($month)->save();
$lesson->update(['month_id' => $month->id]);
Migrations:
Schema::create('months', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('description');
$table->string('price');
$table->timestamps();
});
Schema::create('lessons', function (Blueprint $table) {
$table->increments('id');
$table->integer('month_id')->unsigned();
$table->string('title');
$table->longText('content');
$table->string('file_url');
$table->string('filename');
$table->string('time', 50);
$table->foreign('month_id')->references('id')->on('months')->onDelete('cascade');
$table->timestamps();
});
Firstly, the name of method months() should be renamed to month because it's returning single month not multiple months.
Secondly, If your Lesson has a field called month_id then its far simpler than you are thinking about. We can just change these two lines:
$lesson = Lesson::find($lesson->id);
$lesson->months()->associate($month)->save();
To the following line:
$lesson->update(['month_id' => $month->id);
It should update the month_id of your $lesson to the $month->id
I'm working on a Laravel 5 package, and writing tests I'm trying to test a function that gets datas from DB.
public function getPhotoDatasFromDb()
{
$ret = GalleryImage::get()->keyBy('file_name');
return $ret;
}
The returned values should be in this format:
Collection {#416 ▼
#items: array:2 [▼
"IMG_1979.jpg" => GalleryImage {#423 ▼}
"alt_text" => "example alt text"
"description" => "lorem ipsum"
"IMG_1980.jpg" => GalleryImage {#424 ▶}
]
}
I had already experiences with testing database testing in other Laravel applications.
My question is: since I'm writing a package, and in the dev environment I don't have an instance of the DB I'm wondering what is the best approach to test it?
If can help to have a wider picture, the database table gets created in the application trough this migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateGalleryImagesTable extends Migration
{
public function up()
{
Schema::create('gallery_images', function (Blueprint $table) {
$table->increments('id');
$table->string('file_name')->unique();
$table->text('description')->nullable();
$table->string('alt')->nullable();
$table->string('video_link')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('gallery_images');
}
}
And this is the model associated
<?php
namespace DavideCasiraghi\ResponsiveGallery;
use Illuminate\Database\Eloquent\Model;
class GalleryImage extends Model
{
protected $fillable = [
'file_name', 'description', 'alt', 'video_link',
];
}
I found the solution myself.
I post it in case it can be helpful for somebody else.
This is my test:
/** #test */
public function it_gets_photos_from_db()
{
$gallery = new ResponsiveGalleryFactory();
$dbImageDatas = $gallery->getPhotoDatasFromDb();
$this->assertStringContainsString($dbImageDatas['DSC_9470.jpg']->description, 'Photo description');
}
To make it work I had to configure the DB in the beginning of the testing class:
/**
* Create the tables this model needs for testing.
*/
public static function setUpBeforeClass() : void
{
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
]);
$capsule->setAsGlobal();
$capsule->bootEloquent();
Capsule::schema()->create('gallery_images', function (Blueprint $table) {
$table->increments('id');
$table->string('file_name')->unique();
$table->text('description')->nullable();
$table->string('alt')->nullable();
$table->string('video_link')->nullable();
$table->timestamps();
});
Model::unguard();
GalleryImage::create([
'file_name' => 'DSC_9470.jpg',
'description' => 'Photo description',
'alt_text' => 'Photo alt text',
'video_link' => 'https://www.youtube.com/fsda234',
]);
}
I'm using laravel 5.1.28. Here I'm just trying to create a simple application that can add, delete, and edit products but I noticed that when using the binding model, the $product instance just return null. I'm going to explain next, but first here are the full codes (without blade):
In my route.php I have the following route for product:
Route::model('products', 'App\Product');
Route::group(array('prefix' => 'admin', 'middleware' => 'SentinelAdmin'), function ()
{
# Product Management admin backend
Route::group(array('prefix' => 'products'), function () {
Route::get('/', array('as' => 'products', 'uses' => 'ProductController#index'));
Route::get('create', 'ProductController#create');
Route::post('create', 'ProductController#store');
Route::get('{productId}/delete', array('as' => 'delete/product', 'uses' => 'ProductController#destroy'));
Route::get('{productId}/confirm-delete', array('as' => 'confirm-delete/product', 'uses' => 'ProductController#getModalDelete'));
Route::get('{productId}/restore', array('as' => 'restore/product', 'uses' => 'ProductController#getRestore'));
Route::get('{productId}', array('as' => 'products.show', 'uses' => 'ProductController#show'));
});
Route::resource('products', 'ProductController');
});
So, this is my simple database migration:
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('user_id');
$table->string('name');
$table->string('description')->nullable();
$table->string('category')->nullable();
$table->decimal('price')->nullable();
$table->integer('quantity')->nullable();
$table->tinyInteger('in_stock')->nullable(); //0 - no, 1 - yes
$table->string('photos')->default('default_product_photo.jpg')->nullable(); //add one first
$table->timestamps();
});
}
public function down()
{
Schema::table('products', function (Blueprint $table) {
});
}
}
In my Product.php model, I have this:
**class Product extends Model
{
protected $table = 'products';
protected $guarded = ['id'];
protected $fillable = [
'user_id',
'name',
'description',
'category',
'price',
'quantity',
'in_stock',
'photos',
];
}**
This are the 2 functions that I have in the ProductController.php
For the 1st FUNCTION getModalDelete below, it will find the product id, and display a confirmation box to delete the product. If confirmed button is clicked, the route delete/product/{id} will be called and the destroy method is then called the (2nd function). The 2nd function is matter:
class ProductController extends Controller
{
//1st FUNCTION
public function getModalDelete(Request $request, $id)
{
$product_id = Product::where('id', '=', $id)->firstOrFail();
$model = 'products'; ////testing s
$confirm_route = $error = null;
try {
$confirm_route = route('delete/product', ['id' => $product_id]);
return View('admin/layouts/modal_confirmation', compact('error', 'model', 'confirm_route'));
} catch (ProductNotFoundException $e) {
$error = trans('product/message.error.delete', compact('id'));
return View('admin/layouts/modal_confirmation', compact('error', 'model', 'confirm_route'));
}
}
//2nd FUNCTION
public function destroy(Product $product)
{
Product::destroy($product);
// $product->forceDelete(); //doesn't work either
//dd($product); //Weird that it returns null.
//$success = Lang::get('products/message.success.delete');
//return Redirect::route('admin.products.index')->with('success', $success);
}
}
But if I changed the parameter of the function from
public function destroy(Product $product)
{
}
to
public function destroy($id)
{
}
it works. But I just don't know why the parameter (Product $product) doesn't work here using route model binding. The $product just return null. but the $id returns a value.
Found out it was the issue on front end template:
Actually I tried changing from
Route::model('products', 'App\Product');
to
Route::model('product', 'App\Product');
before attempted to post this question and it did not work due to the issue of the frontend template that I'm using. So, the answers from #Mark Davidson changing the
Route::model('products', 'Product');
to
Route::model('product', 'Product');
and changing the parameter of
{productId}
to
{product}
works perfectly.
The route of deleting the product in the front end has some issue. I can delete the product using the URL browser but clicking on the delete button doesn't popup and I was unable to debug the value. Somehow, the button popup appear if I change the
Route::model('product', 'App\Product');
to
Route::model('products', 'App\Product');
but it returns the $product instance to null. Problem solved.