I'm learning Laravel by creating a recipe website.
The idea is a user creates a recipe which includes a title, description and number of portions (and tags), and then is directed to a new view in which they add the ingredients.
I've got this working, and the user can successfully create the recipe and the ingredients, which are being written to their respective tables, but I'm unable to attach/sync them.
Relevant parts of the models:
Recipe Model:
class Recipe extends Model
{
public function ingredients(){
return $this->hasMany('App\Ingredient', 'recipe_ingredients');
}
}
Ingredient Model:
class Ingredient extends Model
{
public function recipe(){
return $this->belongsTo('App\Recipe', 'recipe_ingredients');
}
}
Ingredients Controller
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255'
]);
$ingredient = new Ingredient;
$ingredient->name = $request->name;
$ingredient->save();
$recipe = Recipe::find($request->id);
$recipe->ingredients()->attach($recipe_id);
$data = [
'success' => true,
'message'=> 'Your AJAX processed correctly',
'name' => $ingredient->name,
'recipe' => $recipe
] ;
return response()->json($data);
}
If I remove the $recipe->ingredients()->attach($recipe_id); the ingredients save to the ingredients table, but I can't get the recipe_id and ingredient_id to save in the recipe_ingredients table`.
I think I'm using the attach wrong, but I could be wrong.
Note:
Not that I think it makes any difference, but I'm submitting the data via Ajax.
Script:
$(document).ready(function(){
$("#submit").click(function() {
var name = $("#ingredientName").val();
var token = $("#token").val();
$.ajax({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
type: "post",
data: "name="+name,
dataType:'json',
url: "{{ route('ingredients.store', ['id' => $recipe->id]) }}",
success:function(data){
console.log(data);
$("#msg").html('<div class="alert alert-success my-0">'+data.name+' added</div>');
$("#msg").toggleClass("invisible")
$("#msg").fadeOut(2000);
$("#ingredientsTable").append('<tr><td scope="col" class="align-middle">'+data.name+'</td></tr>');
}
});
})
})
Revised Controller
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255'
]);
$ingredient = new Ingredient;
$ingredient->name = $request->name;
$ingredient->save();
$recipe = Recipe::find($request->id);
$recipe->ingredients()->attach($ingredient->id);
$data = [
'success' => true,
'message'=> 'Your AJAX processed correctly',
'name' => $ingredient->name,
'recipe' => $recipe
] ;
return response()->json($data);
}
Table migration
public function up()
{
Schema::create('recipe_ingredients', function (Blueprint $table) {
$table->integer('recipe_id')->unsigned();
$table->foreign('recipe_id')->references('id')->on('recipes');
$table->integer('ingredient_id')->unsigned();
$table->foreign('ingredient_id')->references('id')->on('ingredients');
});
}
You're using the wrong ID when trying to attach the Ingredient to the Recipe:
$ingredient = new Ingredient;
$ingredient->name = $request->name;
$ingredient->save();
$recipe = Recipe::find($request->id);
$recipe->ingredients()->attach($recipe_id);
In the last line, you already have the Recipe, so passing $recipe_id (which I actually don't see defined anywhere) is not the correct logic.
What you need to do is pass the Ingredient you want to attach:
$recipe->ingredients()->attach($ingredient->id);
That should correctly set the relationship.
As shown by the example here: https://laravel.com/docs/5.6/eloquent-relationships#updating-many-to-many-relationships
You should be attaching the ingredients instead of the recipe:
$recipe->ingredients()->attach($ingredient_id);
-- edit --
You also have your Ingredient model as:
class Ingredient extends Model
{
public function ingredient(){
return $this->belongsToMany('App\Recipe', 'recipe_ingredients');
}
}
However, you should have this instead:
public function recipes(){
return $this->belongsToMany('App\Recipe', 'recipe_ingredients');
}
After making lots of little tweaks and changes, the following finally worked for me:
Recipe /model:
class Recipe extends Model
{
public function ingredients(){
return $this->hasMany('App\Ingredient', 'recipe_ingredients', 'recipe_id', 'ingredient_id');
}
Ingredient Model:
class Ingredient extends Model
{
public function recipes(){
return $this->belongsToMany('App\Recipe', 'recipe_ingredients', 'ingredient_id', 'recipe_id');
}
**IngredientsController#Store: **
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255'
]);
$ingredient = new Ingredient;
$ingredient->name = $request->name;
$ingredient->save();
$recipe = Recipe::find($request->id);
$ingredient->recipes()->attach($recipe->id);
$data = [
'success' => true,
'message'=> 'Your AJAX processed correctly',
'name' => $ingredient->name,
'recipe' => $recipe
] ;
return response()->json($data);
}
Related
Newbie to all the tech I'm using here.
Trying to query a table using Axios in Laravel with Vue.js. Here's what I got:
from my component's <script>
this.axios
.get('http://localhost:8000/api/tasks', {params: {vid: this.properties[0].vid}})
.then(response => {
this.tasks = response.data;
console.log(response)
})
Regardless of what vid is in the params, the response contains ALL of the table's rows.
I do know that this may have something to do with api.php, and the Controller associated with the request. I'll post those to be verbose.
routes/api.php
Route::middleware('api')->group(function () {
Route::resource('vehicles', VehicleController::class);
Route::resource('tasks', TaskController::class);
Route::get('tasks?={vid}', [TaskControler::class, 'search']);
});
Controllers/TaskController.php
class TaskController extends Controller
{
//
public function index() {
$tasks = Task::all()->toArray();
return $tasks;
}
public function store(Request $request){
$task = new Task([
'make' => $request->input('make'),
'model' => $request->input('model'),
'year' => $request->input('year'),
'mileage' => $request->input('mileage'),
'type' => $request->input('type'),
'VIN' => $request->input('VIN')
]);
$task->save();
}
public function show($tid){
$task = Task::find($tid);
return response()->json($task);
}
public function update($tid, Request $request){
$task = Task::find($tid);
$task->update($request->all());
return response()->json('Task Updated!');
}
public function destroy($tid){
$task = Task::find($tid);
$task->delete();
return response()->json('Task Deleted!');
}
}
I tried for a while to mess around with api and the controller, but to no avail. Most of the questions asked here give "just use params" as an answer, but despite my best efforts I don't seem to be able to get away with "just" params (willing to be proven wrong.)
I am new on Laravel 6 and would like to add data to a column. I have a table called 'projects'. This table has a column named 'comments'. My purpose is to only add data to the 'comments' column by updating a project.
I have a ProjectController containing a method storeComment which is as follows:
public function storeComment(Request $request, Project $project)
{
$validData = $request->validate([
'project_id' => 'required',
'comments' => 'required'
]);
$project->comments = $validData['comments'];
$project->save();
return redirect('home')->with('status', 'Comment created successfully');
}
The problem is that the method creates a new record instead of updating an existing one. Is there anybody who could help? Thanks in advance
public function updateComments(Request $request, $id)
{
$projects = Project::find($id);
$projects->comments = $request->comments;
$projects->save();
}
You need to fetch the record first, then update comments of that record like this:
use App\Project;
public function storeComment(Request $request) {
$request->validate([
'project_id' => 'required',
'comments' => 'required'
]);
$project = Project::find($request->project_id);
$project->comments = $request->comments;
$project->save();
return redirect('home')->with('status', 'Comment created successfully');
}
I did a register of users in my own controller, i want the id of the user i just added because i want to use it in another table in that same controller and function
Below i will let the code of how i tried but doesn't work i want to know how could i do that
I want something like this $usuario->fk_cliente_natural=$cliente_natural->id_cliente_natural; but sais that $cliente_natural->id_cliente_natural is null because i dont get the last id
Code of my store function()
public function store(Request $request)
{
$cliente_natural=new Cliente_natural();
$cliente_natural->primer_nombre=$request->primer_nombre;
$cliente_natural->segundo_nombre=$request->segundo_nombre;
$cliente_natural->primer_apellido=$request->primer_apellido;
$cliente_natural->segundo_apellido=$request->segundo_apellido;
$cliente_natural->cedula=$request->cedula;
$cliente_natural->rif=$request->rif;
$cliente_natural->numero_carnet=$request->numero_carnet;
$usuario=new Usuario();
$this->validate(request(), [
'email' => 'required|email',
'password' => 'required|confirmed|min:8',
]);
$cliente_natural->save();
$usuario->email=$request->email;
$usuario->password=$request->password;
$usuario->fk_rol=3;
$usuario->fk_cliente_natural=$cliente_natural->id_cliente_natural;
//$cliente_natural->fk_lugar=getMunicipio();
$usuario->save();
return view('home.home2');
}
Code of my create function()
public function create()
{
$cliente_natural = DB::select( DB::raw("SELECT id_cliente_natural,rif, numero_carnet,cedula,primer_nombre,
segundo_nombre,primer_apellido,segundo_apellido,fk_lugar,password,
email,fk_rol,id_usuario,fk_cliente_natural
FROM cliente_natural,usuario"
));
return view('auth.register')->with('cliente_natural',$cliente_natural);
}
This is how i solve it
//$usuario->fk_cliente_natural = $cliente_natural->id_cliente_natural;
$checkT = DB::select(DB::raw("SELECT id_cliente_natural as id from cliente_natural WHERE rif = '$cliente_natural->rif' AND numero_carnet = '$cliente_natural->numero_carnet'"));
$id = $checkT[0]->id;
$usuario->fk_cliente_natural = $id;
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 problem with saving data to m:n table layout in laravel 5. I have table appliances and table documentations, where pivot table is documentation_appliance.
Models are:
class Appliances extends Model
{
public function documentations()
{
return $this->belongsToMany('documentations');
}
}
and
class Documentation extends Model
{
public function appliances()
{
return $this->belongsToMany('appliances');
}
}
Now I try to save data to table in my Controller
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'file_name' => 'required',
]);
if($request->hasFile('file_name') ) {
$fname = $request->file('file_name')->getClientOriginalName();
$request->file('file_name')->move(
base_path() . '/public/files/documentation/', $fname
);
}
$document = new Documentation();
$document->name = $request->name;
$document->filename = $fname;
if($document->save()) {
$doc_ids = $request->documentation_appliance;
$document->appliances()->sync($doc_ids);
}
return view('backend.documentation.index', [
'documentations' => $this->documents->getDocuments(),
]);
}
Data to table documents are saved corectly, image is stored, but I have problem with saving data to pivot table. Screen displays me this error:
FatalErrorException in compiled.php line 10191:
Class 'appliances' not found
in compiled.php line 10191
nothing more, I guess I have bad use of class somewhere or am I doing bad something else? Thanks everyone for help.
according to https://laravel.com/docs/5.2/eloquent-relationships#many-to-many your table name must be appliance_documentation not documentation_appliance.