I'm building a web app with laravel.
First Question:
There's a simple form on users dashboard to fill and save.
Here's the model:
class Salon extends Model
{
protected $table = 'salons';
protected $fillable = [
'salonname', 'saloncity', 'salonaddress', 'salontel', 'salonmob', 'salonsite', 'saloncat', 'salonkhadamat', 'salonkhadamatprice', 'salondesc', 'saloninsta', 'salontelegram', 'salontags'
];
public $timestamps = false;
}
and here is the controller :
public function store(Request $request)
{
$user_id = Auth::user()->id;
Salon::create([
'user_id' => $user_id,
'salonname' => $request['salonname'],
'saloncity' => $request['saloncity'],
'salonaddress' => $request['salonaddress'],
'salontel' => $request['salontel'],
'salonmob' => $request['salonmob'],
'salonsite' => $request['salonsite'],
'saloncat' => $request['saloncat'],
'salonkhadamat' => $request['salonkhadamat'],
'salonkhadamatprice' => $request['salonkhadamatprice'],
'salondesc' => $request['salondesc'],
'saloninsta' => $request['saloninsta'],
'salontelegram' => $request['salontelegram'],
'salontags' => $request['salontags']
]);
return 'done!';
}
And the routes:
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/salons/add', function () {
return view('add_salon');
})->middleware('auth');
Route::post('salons', 'SalonsController#store');
Route::get('salons', function () {
return 'Hi';
});
When I complete the form and hit send button, it returns this error :
"SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into salons (salonname,...
Where am I doing wrong?
I created a table migration as :
public function up()
{
Schema::create('Salons', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->string('salonname');
$table->string('saloncity');
$table->string('salonaddress');
$table->integer('salontel');
$table->integer('salonmob');
$table->string('salonsite');
$table->string('saloncat');
$table->string('salonkhadamat');
$table->integer('salonkhadamatprice');
$table->string('salondesc');
$table->string('saloninsta');
$table->string('salontelegram');
$table->string('salontags');
$table->timestamps();
});
}
user_id is using a foreign reference from users table.
let me explain the process, consider we have some users registered on our app, some of them want to add their salons on our website, so we want to use the user_id from the users table on salons table, so we can return salons with the user's data (profile) on our homepage.
Second question:
If a salon have two separate telephone numbers, How can I store them in this table separately? I mean, people can add many telephone-numbers as they want. Or as many addresses as they have, in separate fields.
Third question:
For creating a portfolio section for each salon, Should I create a new table such as attachments to have pictures addresses and salon id to return them on their respective page later?
Add user_id to the fillable array too:
protected $fillable = ['user_id', 'salonname', 'saloncity', 'salonaddress', 'salontel', 'salonmob', 'salonsite', 'saloncat', 'salonkhadamat', 'salonkhadamatprice', 'salondesc', 'saloninsta', 'salontelegram', 'salontags'];
Or use the relationship if it is defined:
$salon = auth()->user()->salons()->create([....
If it's not defined:
public function salons()
{
return $this->hasMany(Salon::class);
}
Related
I have two models Batch and Notices. The foreign key is correctly formed and data is saved in the database. Now I can't show the data on my listing blade.
Notice Migration:
Schema::create('notices', function (Blueprint $table) {
$table->id();
$table->string('noticeTitle');
$table->string('noticeDesc');
$table->string('file')->nullable();
$table->unsignedBigInteger('batch_id');
$table->foreign('batch_id')->references('id')->on('batches');
$table->timestamps();
});
Batch Migration:
Schema::create('batches', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Data dump from db is:
"id" => 1
"noticeTitle" => "Quae ea est temporib"
"noticeDesc" => "<p>sa</p>"
"file" => null
"batch_id" => 2
"created_at" => "2020-07-27 16:09:52"
"updated_at" => "2020-07-27 16:09:52"
]
Notice model
public function batches()
{
return $this->belongsTo(Batch::class);
}
Batch Model
public function notice()
{
return $this->hasMany(Notice::class);
}
Notice controller
public function index(){
$notices = Notice::all();
return view('admin.notice.list')
->with('notices', $notices);
}
public function store(Request $request)
{
$this->validate($request, [
'noticeTitle' => 'required',
'noticeDesc' => 'required',
]);
$notice = new Notice;
$notice->noticeTitle = $request->input('noticeTitle');
$notice->noticeDesc = $request->input('noticeDesc');
$notice->batch_id = $request->input('targetedGroup');
if($request->hasFile('file')) {
$noticeTitle = $request->input('noticeTitle');
$filename = $request->file->getClientOriginalName();
$request->file->storeAs('public/noticeFile/additionalFiles', $noticeTitle.'_'.$filename);
$path = $noticeTitle.'_'.$filename;
$notice->file = $path;
}
try{
$notice->save();
Session::flash('success', 'Notice Saved');
return redirect()->route('notice.index');
}
catch (\Throwable $th){
Session::flash('danger', 'Something went wrong');
return redirect()->route('notice.index');
}
}
Now I want to get batch name from batch_id
First, you might want to change the function names of your relationships. Your notice has only one batch, so it should be public function batch() and a batch has several notices, so public function notices().
You can acces your relationships like any attribute, so in your blade:
#foreach($notices as $notice)
#php $batch = $notice->batch; #endphp
{{$batch->name}}
#endforeach
Or even shorter (if you don't plan on using the related batch for anything else)
#foreach($notices as $notice)
{{$notice->batch->name}}
#endforeach
This is all explained in the Laravel documentation: https://laravel.com/docs/7.x/eloquent-relationships
I am creating factories and saving the page model to the film model so its film to page one-to-many,
i've followed the docs but when im trying to save the models to each other i am getting this error
General error: 20 datatype mismatch (SQL: insert into "pages" ("id", "page_url", "film_id", "updated_at", "created_at") values (591d61cb-3090-3945-b920-ba797245cb97, http://larson.com/, bd3bab38-f8be-4674-ae5d-15e8f6b6172a, 2019-11-15 11:23:02, 2019-11-15 11:23:02))
These are the classes i am working with
Film migration
public function up()
{
Schema::create('films', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name');
$table->string('description');
$table->timestamps();
});
}
Pages migration
public function up()
{
Schema::create('pages', function (Blueprint $table) {
$table->bigIncrements('id');
$table->uuid('film_id')->nullable();
$table->string('page_url')->nullable();
$table->timestamps();
});
}
PagesFactory
$factory->define(Pages::class, function (Faker $faker) {
return [
'id' => $faker->uuid,
'page_url' => $faker->url,
'film_id' => factory(\App\Models\Film::class)->create()->id
];
Pages model
public function film(): BelongsTo
{
return $this->belongsTo(Film::class);
}
FilmController
*/
public function show(string $id)
{
$film = Film::with([
'pages',
'languages',
'categories',
])->findOrFail($id);
return $film;
FilmControllerTest
public function getFilmTest()
{
$film = factory(Film::class)->create();
$language = Language::where('id', 'en')->where('name', 'English')->first();
$categories = Category::where('main-cat', 'Science')->where('sub-cat', 'Fiction')->first();
$film->pages()->save(factory(Page::class)->create());
$film->languages()->attach($language->id);
$film->categories()->attach($categories->id);
$response = $this->json('GET', '/film/' . $film->id)
->assertStatus(200);
$response
->assertJson(['id' => $guestProfile->id])
->assertJson(['name' => $film->description])
->assertJson(['languages' => $film->languages->toArray()])
->assertJson(['categories' => $film->categories->toArray()])
}
when i comment out this line from the test it works fine $film->pages()->save(factory(Page::class)->create());
im abit lost on why im having this issue trying to save the models so the pages becomes part of the response... can i get some help/example please :D
The id of your pages table is set to a bigIncrements (UNSIGNED BIGINT), but in your PagesFactory you are trying to store a uuid.
$factory->define(Pages::class, function (Faker $faker) {
return [
'id' => $faker->uuid,
'page_url' => $faker->url,
'film_id' => factory(\App\Models\Film::class)->create()->id
];
Remove 'id' => $faker->uuid, from the factory, you don't have to set an auto incrementing field.
Another option (depending on the design you have in mind) is to change the migration of the pages table and set the id column to $table->uuid('id')->primary();
try using the make() method, as in:
$film->pages()->save(factory(Page::class)->make());
I'm working on laravel e-commerce project where I need to add Attributes to my posts (image below as example)
My question is how to achieve that? should i create new tables or can I add manually from post.create like any other e-commerce cms?
Personally I prefer to be able to add fields in post.create like I
add + button and each time I click on it 2 input fields add and I
can put key and value in it. (if you can help me with that)
Thanks.
Update:
With suggest of #anas-red I've created this structure now:
attributes table.
Schema::create('attributes', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->unique();
$table->timestamps();
});
and product_attributes table
Schema::create('product_attributes', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products');
$table->integer('attribute_id')->unsigned();
$table->foreign('attribute_id')->references('id')->on('attributes');
$table->string('attribute_value')->nullable();
$table->timestamps();
});
now i have this store method on my controller when i save my posts:
public function store(Request $request)
{
//Validating title and body field
$this->validate($request, array(
'title'=>'required|max:225',
'slug' =>'required|max:255',
'user_id' =>'required|numeric',
'image_one' =>'nullable|image',
'image_two' =>'nullable|image',
'image_three' =>'nullable|image',
'image_four' =>'nullable|image',
'image_one' =>'nullable|image',
'short_description' => 'nullable|max:1000',
'description' => 'nullable|max:100000',
'subcategory_id' => 'required|numeric',
'discount' => 'nullable|numeric',
'discount_date' => 'nullable|date',
'price' => 'required|numeric',
));
$product = new Product;
$product->title = $request->input('title');
$product->slug = $request->input('slug');
$product->user_id = $request->input('user_id');
$product->description = $request->input('description');
$product->short_description = $request->input('short_description');
$product->subcategory_id = $request->input('subcategory_id');
$product->discount = $request->input('discount');
$product->discount_date = $request->input('discount_date');
$product->price = $request->input('price');
if ($request->hasFile('image')) {
$image = $request->file('image');
$filename = 'product' . '-' . time() . '.' . $image->getClientOriginalExtension();
$location = public_path('images/');
$request->file('image')->move($location, $filename);
$product->image = $filename;
}
$product->save();
$product->attributes()->sync($request->attributes, false);
//Display a successful message upon save
Session::flash('flash_message', 'Product, '. $product->title.' created');
return redirect()->route('admin.products.index');
}
The process i want to do is this:
Store my attributes
Select my attributes while creating new post
Give value to selected attribute
save post_id arribute_id and atteribute_value in product_attributes table.
here is the error i get:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'attributes_id'
in 'field list' (SQL: select attributes_id from product_attributes
where product_id = 29)
UPDATE:
Product model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use jpmurray\LaravelCountdown\Traits\CalculateTimeDiff;
class Product extends Model
{
use CalculateTimeDiff;
protected $table = 'products';
protected $fillable = [
'title', 'slug', 'image_one', 'image_two', 'image_three', 'image_four', 'short_description', 'description', 'price', 'discount', 'discount_date',
];
public function category(){
return $this->belongsTo(Category::class);
}
public function subcategory(){
return $this->belongsTo(Subcategory::class);
}
public function attributes()
{
return $this->belongsToMany(Attribute::class, 'product_attributes', 'product_id', 'attribute_id');
}
public function order(){
return $this->hasMany(Order::class);
}
public function discounts(){
return $this->hasMany(Discount::class, 'product_id', 'id');
}
}
Attribute model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Attribute extends Model
{
protected $fillable = [
'title',
];
public function products(){
return $this->belongsToMany(Product::class);
}
}
I think you can add new table lets say "post_attributes" with the following columns:
id - post_id - key - value
in the PostAttribute model add this:
public function post
{
return $this->belongsTo(Post::class);
}
in the Post model add the following:
public function attributes
{
return $this->hasMany(PostAttributes::class, 'post_attributes');
}
Now the app is flexible enough to handle multiple attributes to one post or a single attribute to another.
Other approach is to implement JSON in your database. Hope that helped you.
update Product model
public function attributes()
{
return $this->belongsToMany(Attribute::class, 'product_attributes', 'product_id', 'attribute_id')->withPivot('attribute_value')->withTimestamps();
}
and update Attribute model to
public function products()
{
return $this->belongsToMany(Product::class, 'product_attributes', 'attribute_id', 'product_id')->withPivot('attribute_value')->withTimestamps();
}
If I see your Product and Attribute Models I will be in a better position to answer you properly.
But any way, I think your problem is with the product_attributes table.
This table is now acting as a pivot (intermediate) table and it is not following Laravel naming convention. The convention is to name it as follows: attribute_product.
Next, you have to add the following into both models i.e. Product and Attribute.
in Attribute Model add:
$this->belongsToMany(Product::class)->withPivot('value');
in Product Model add:
$this->belongsToMany(Attribute::class)->withPivot('value');
To add value to more_value column on pivot table. Use the following:
$product->attributes()->attach($attributeId, ['more_value' => $string]);
or use sync:
$product->attributes()->sync([$attributeId => ['more_value' => $string]]);
lol. the important part is repo code is:
<input type="hidden" id="appOrderItems" name="orderItems[]">
trace appOrderItems in my JS section and you will get it.
in simple words:
when the user adds attributes to a product (in my case, items to an order) then, the appOrderItems array will get the id of the attribute and any additional value that you need to add into the pivot table (other than the product_id and attribute_id. in your case the mores_value). After gathering these attributes into appOrderItems JS array I push its value to the hidden HTML field (name="orderItems[]"). in this case it will be sent to the controller for further process.
I have user input following the rules below;
public function rules()
{
return [
'phone_number' => 'required|array',
'amount' => 'required|string|max:4',
'phone_number_debit' => 'required|string|max:15',
];
}
I would want to save the data in a model Transaction. For the phone_number it is an array that could have one value or multiple. So that leaves for foreach loop.
This is what I want to achieve, save different rows determined by the number of records in the array.
$transaction = new Trasaction();
$transaction->phone_number = $req->phone_number; //Value in the array
$transaction->amount = $req->amount;
$transaction->phone_number_debit = $req->phone_number_debit;
$transaction->save();
Save diffrent records according to the records in the phone_number array.
However I can not think of a way to achieve this.
Anyone?
try this :
$data = request(['amount', 'phone_number', 'phone_number_debit']);
foreach($data['phone_number'] as $phone_number) {
Trasaction::create([
'amount' => $data['amout'],
'phone_number' => $phone_number,
'phone_number_debit' => $data['phone_number_debit']
]);
}
make sure in your Trasaction modal you've set to fillable property like this :
class Trasaction extends Model
{
protected $fillable = ['amount', 'phone_number', 'phone_number_debit'];
}
There are many ways to do this, in a nutshell:
collect(request('phone_number'))->each(function ($phone) use ($req) {
$transaction = new Trasaction();
$transaction->phone_number = $phone; // element of the array
$transaction->amount = $req->amount;
$transaction->phone_number_debit = $req->phone_number_debit;
$transaction->save();
});
TL;DR
One-to-Many Relationship
In order to get a better code, you can create a transaction_phones table, creating a one-to-many relationship.
You'll create a TransactionPhone model and add this:
public function transaction()
{
return $this->belongsTo(Transaction::class);
}
The TransactionPhone migration:
Schema::create('transaction_phones', function (Blueprint $table) {
$table->increments('id');
$table->integer('transaction_id');
$table->string('phone_number');
$table->timestamps();
});
In your Transaction model you'll have the inverse:
public function phones()
{
return $this->hasMany(TransactionPhone::class);
}
public function addPhone($phone)
{
return $this->phones()->create(['phone_number' => $phone]);
}
And in you Controller:
$transaction = Trasaction::create(request()->only('amount', 'phone_number_debit'));
collect(request('phone_number'))->each(function ($phone) use ($transaction) {
$transaction->addPhone($phone);
});
I hope this answer can help you.
I can get the current user that logged in. But I don't know how can I passed this into variable. I can the user id by this.
public function getDocuments()
{
//GETTING ALL THE ID OF THE USERS IN THE DATABASE EXCEPT THE ID OF CURRENT USER.
$resultRecipient = DB::table('users')->where('id', '!=', Auth::id())->get();
//GETTING ALL THE CATEGORIES.
$resultCategory = DB::table('categories')->get();
//VIEW
return view ('document.create')->with('resultRecipient', $resultRecipient)->with('resultCategory', $resultCategory);
if(\Auth::user()->id)
{
echo "You get the id";
}
else
{
echo "Failed";
}
}
Can anyone tell me how can I sync the current user id when the submit button is submitted. Is there a way how can I attach the id of the user in the sync method?
public function postDocuments(Request $request)
{
$this->validate($request,
[
'title' => 'required|alpha_dash|max:255',
'content' => 'required',
'category_id' => 'required',
'recipient_id' => 'required',
]);
$document = new Document();
//Request in the form
$document->title = $request->title;
$document->content = $request->content;
$document->category_id = $request->category_id;
$document->save();
$document->recipients()->sync($request->recipient_id, false);
return redirect()->back();
}
UPDATE!
According to #Ariful. I can add the instance of Auth::user(); to get the id. But it doesn't return me the id to my pivot table and gives me a error.
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (webdev.document_user, CONSTRAINT document_user_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE) (SQL: insert into document_user (document_id, user_id) values (59, 0))
public function postDocuments(Request $request)
{
$this->validate($request,
[
'title' => 'required|alpha_dash|max:255',
'content' => 'required',
'category_id' => 'required',
'recipient_id' => 'required',
]);
$user = Auth::user();
$document = new Document();
//Request in the form
$document->title = $request->title;
$document->content = $request->content;
$document->category_id = $request->category_id;
$document->save();
$document->recipients()->sync([$request->recipient_id, $user->id, false]);
return redirect()->back();
}
Models:
User Model
class User extends Model implements AuthenticatableContract
{
public function documents()
{
return $this->belongsToMany('App\Models\Document', 'document_user', 'user_id', 'document_id');
}
}
Document Model:
class Document extends Model
{
public function recipients()
{
return $this->belongsToMany('App\Models\User', 'document_user', 'document_id', 'user_id');
}
}
Migration:
User migration
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('first_name');
$table->string('last_name');
$table->string('middle_name');
$table->string('email');
$table->string('username');
$table->string('address');
$table->string('password');
});
}
Documents migration:
public function up()
{
Schema::create('documents', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('content');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
}
documents_user migration:
public function up()
{
Schema::create('document_user',function (Blueprint $table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('document_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('document_id')->references('id')->on('documents')->onDelete('cascade');
$table->unsignedInteger('sender_id')->nullable();
$table->foreign('sender_id')->references('id')->on('users')->onDelete('cascade');
$table->dateTime('dateReceived')->default(DB::raw('CURRENT_TIMESTAMP'));
});
}
Screenshot Database:
UPDATE 2:
I can insert a values on my user_id based on the user's choice in the select list.
This is where the values of the form inserted in the user_id column. I just need to insert the current user in my sender_id so I can determined who send the data.
<div class = "form-group">
<label for = "recipient_id" class = "control-label">To:</label>
<select name = "recipient_id[]" multiple class = "form-control" id = "myUserList">
#foreach ($resultRecipient as $list)
<option value = "{{ $list->id }}">{{ $list->username }}</option>
#endforeach
</select>
</div>
As you can see here I just insert this manually based on the users table data. Still don't have idea how can I insert the current user into sender_id column.
I believe this should work
$user = Auth::user(); //get current user
$document->recipients()->sync([$user->id]);
UPDATED Source Link
$document->recipients()->sync( [ $request->recipient_id, $user->id ], false );
As per documentation,
The sync method accepts an array of IDs to place on the intermediate table.
UPDATE 2
$document->recipients()->sync( [ $request->recipient_id =>
['sender_id' => $user->id] ],
false );
Your sender_id is not part of your relationship. So you need to add it as extra info.
UPDATE 3
After discussion, this should be your main code
foreach($request->recipient_id as $receipentId){
$document->recipients()->sync( [ $receipentId =>
['sender_id' => $user->id] ],
false );
}
This will loop through your receipent_id array and take each id for sync with the current logged in user as $user->id;