I'm pretty sure this is a noob question, even though I'm used to PHP, but not to Laravel
My goal can't be any more simple, I'd like to be able to write an article and add an image to it, but even though I made the upload system work (that wasn't a piece of cake), I'm having issues with saving the filename itself.
Here's how I proceeded:
use App\Photo;
use Illuminate\Http\Request;
use Intervention\Image\Facades\Image;
public function store(Request $request)
{
$file = $request->file('image');
$originalname = $file->getClientOriginalName();
$path = 'uploads/' . $originalname;
Image::make($file)->save($path);
$product = new Photo(array(
'name' => $request->get('name'),
'image' => $originalname
));
$product->save();
return \Redirect::route('photo.index', array($product->id))->with('message', 'Product added!');
}
And here is my migration file, if this can help:
public function up()
{
Schema::create('photos', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('image');
$table->timestamps();
});
}
So I wanted to save the filename as a string inside the database so I could call it later, like with $product->image, however I'm getting the following error:
SQLSTATE[HY000]: General error: 1364 Field 'image' doesn't have a default value (SQL: insert into `photos` (`name`, `updated_at`, `created_at`) values (sisdjfposd, 2017-05-31 22:42:18, 2017-05-31 22:42:18))
So I know what it means, and I don't like it because it was supposed to have a value: if I add die($originalname);before the line $product = new Photo array(, i get my filename so logically the variable isn't empty.
So why would I have this error? Am i missing something?
Thank you in advance
I think you have missed adding image fields into mass assignment.
In your Photo model just add:
protected $fillable = ['name', 'image'];
More info on mass assignment:
https://laravel.com/docs/5.4/eloquent#mass-assignment
Related
So I have 2 tables: Item and Product. An Item hasMany Products and a Product belongsTo an Item.
Products migration:
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('hashed_id')->nullable()->unique();
$table->bigInteger('item_id')->unsigned();
$table->bigInteger('user_id')->unsigned();
$table->integer('state')->default(1);
$table->decimal('price');
$table->string('slug')->nullable()->unique();
$table->timestamps();
$table->foreign('item_id')->references('id')->on('items')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
For the hashed_id I use the following package: https://packagist.org/packages/hashids/hashids to create a hashed id to show in the url.
Product.php
public static function boot()
{
parent::boot();
static::created(function ($product) {
$productId = $product->id;
$hashids = new Hashids("", 10, 'abcdefghijklmnopqrstuvwxyz1234567890');
$hashedId = $hashids->encode($productId++);
$slug = Str::slug($product->item->slug . '-' . $hashedId);
$product->hashed_id = $hashedId;
$product->slug = $slug;
});
}
ProductsController.php
public function createSelfProduct(Request $request)
{
$product = auth()->user()->products()->create([
'item_id' => $request->item_id,
'user_id' => auth()->user()->id,
'price' => $request->price,
]);
// create the product and show seller info
return new ProductResource($product->load('user'));
}
What I'm trying to do is that when a user creates a new product, it should get the slug from the item model, put the $hashedId behind it and save that to the db. Now, when I do a post request via Postman, I get the desired result, as hashed_id and slug are saved. But when I check the database, both hashed_id and slug are NULL. Only the item_id, user_id and price are saved. What am I doing wrong and how can I fix this?
The created event means the Model has already been created. This is not before save, but after it has been saved. If you alter anything at this point you will need to save the record again.
Simply: You forgot to call save on your model instance to save the changes after you altered it.
Laravel has a convenient way of handling this with Observers
https://laravel.com/docs/5.8/eloquent#observers
php artisan make:observer ProductObserver
Then in Observers/ProductObserver.php
public function created(Product $product) {
$product = ''; // whatver you need to do here. $product is an instance of Product model
// Dont forget to save your model after modifying
$product->save();
}
Hi i'm trying to make a function that allows everyone to publish whatever they want but when the visitor is not a user his post photo's default will be a photo from my directory storage that holds the meaning of anonymous or something alike:
what is the SQL command line that allows me to do so?
My post migration table is:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('username');
$table->string('body');
$table->boolean('valid')->default(0);
$table->string('photo',150)->nullable();
$table->timestamps();
});
My function store() is the following:
public function store(Request $request)
{
$post= new Post();
$post->title=$request->input('title');
$post->photo=$request->photo; //what do i change in this field?
$post->username=$request->input('username');
$post->body=$request->input('body');
$post->save();
return redirect ('/ed');
}
Any ideas would be appreciated, thank you
You can use this:
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// The user is logged in...
$postPhoto = $request->photo
} else{
//photo from directory storage
$postPhoto = public_path('/images/default.jpg');
}
// store photo in the database
$post->photo = $postPhoto;
#Wellwisher is right! But you can also set a default value to the photo field at posts table (and that is if you not planning to change the image name).
$table->string('photo', 150)->default('avatar.jpg');
and you will overwrite (change) it in case user uploads a new image as his/her profile image.
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 am using dimsav for multilanguage and I have this problem after doing step by step from the guid. (dimsav)
I have a Model Category:
use Illuminate\Database\Eloquent\Model;
use Dimsav\Translatable\Translatable;
class Category extends Model {
use Translatable;
public $translatedAttributes = ['name'];
}
A CategoryTranslation:
use Illuminate\Database\Eloquent\Model;
class CategoryTranslation extends Model {
public $timestamps = false;
}
And in Controller when I try to save this with a specific language I get an error. This is my controller:
$language = App::getLocale();
$user = Auth::user();
$category = new Category();
$category->translate('en')->name = Input::get('name'); //line 35
$category->save())
And error:
at HandleExceptions->handleError('2', 'Creating default object from
empty value',
'C:\workspace\applications\wamp\www\lutz-paletten\app\Http\Controllers\CategoryController.php',
'35', array('language' => 'en', 'user' => object(User), 'category' =>
object(Category))) in CategoryController.php line 35
PS: this is my migration:
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->integer('categoryId');
$table->integer('user_id');
$table->timestamps();
});
Schema::create('category_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->string('name');
$table->string('locale')->index();
$table->unique(['category_id','locale']);
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
});
What am I missing ?
If I use this, it works:
$category->name = Input::get('name');
And it will be saved with what is set as AppLocale but how can I use it with translate() ?
I don't know if you solved this or not, but i think you should check with a couple of things:
1- delete the Parentheses when initiating the Category object so it will become:
$category = new Category;
2- Change the extra Parentheses after the save function so it will be:
$category->save();
3- make sure your input is named correctly.
and that's all i can see, hope you solved already :).
BTW you don't need that
$table->integer('categoryId'); in your migration is not nessary since $table->increments('id); is playing that role!
happy coding :)
If you create a new record of Category, this last one saves record with your current Locale (default : en).
You just need to change $category->translate('en') by $category->getNewTranslation('en') or $category->translateOrNew('en') and it works !
For your example:
Create a category with default locale (config/app.php ==> locale => 'en'):
// CategoryController
public function createCategory(Request $request)
{
// Save record in *categories* table
// And save the default language (config/app.php ==> locale) in *category_translations* table.
$category = new Category::create($request);
}
Create a translation in an existing category:
public function createCategoryTranslation(Request $request, $id)
{
$category = Category::find($id)
// Solution 1 : If you want to explain the fields to be saved.
$category->getNewTranslation('en')->name = $request->input('name');
// Solution 2 : Mass assignement if you have multiple fields to be saved.
$category->getNewTranslation('en')->fill($request);
$category->save()
}
Update a translation:
public function updateCategoryTranslation(Request $request, $id)
{
$category = Category::find($id)
// Solution 1 : If you want to explain the fields to be saved.
$category->translate('en')->name = $request->input('name');
// Solution 2 : Mass assignement if you have multiple fields to be saved.
$category->translate('en')->fill($request);
$category->save()
}
CreateOrUpdate translation:
public function createOrUpdateCategoryTranslation(Request $request, $id)
{
$category = Category::find($id)
// Solution 1 : If you want to explain the fields to be saved.
$category->translateOrNew('en')->name = $request->input('name');
// Solution 2 : Mass assignement if you have multiple fields to be saved.
$category->translateOrNew('en')->fill($request);
$category->save()
}
i have been able to follow this answer and i can actually create multiple image size.
My question is, how can i save each path to a database.
public function store(Request $request)
{
$input= $request->all();
$file = $input['image'];
$destinationPath='images/products';
$destinationPathlarge='images/products/large';
$extension = $file->getClientOriginalExtension();
$fileName = rand(111,999).'.'.$extension;
$image = $destinationPath . '/' .$fileName;
$upload_success= $file-> move($destinationPath,$fileName);
$doc = new Products();
$doc->name = $input['name'];
$doc->price = $input['price'];
$doc->description = $input['description'];
$doc->s_description = $input['s_description'];
$doc->brands_id = $input['brands_id'];
$doc->categories_id = $input['categories_id'];
$upload = Image::make($image)->resize(190,185)->save($destinationPath. '/' .$fileName)
->resize(100,100)->save($destinationPathlarge. '/'.$fileName);
$doc->save();
You should create an appropriate Eloquent model.
First, run an artisan command in your project's folder.
php artisan make:model MyImage
This will create the 'MyImage' Eloquent Model and it's database migration.
Edit the newly created migration file by adding new path fields to the up() function like this:
Schema::create('my_images', function(Blueprint $table)
{
$table->increments('id');
$table->string('path_190');
$table->string('path_100');
$table->timestamps();
});
Run the new migration to make the changes to your database.
Then, in the App\MyImage model class, add the fillable property to enable filling of the path fields:
class Image extends Model {
protected $fillable = [
'path_100',
'path_190',
];
}
Now add to your Controller's store action:
App\MyImage::create([
'path_100' => asset($destinationPathlarge. '/'.$fileName100),
'path_190' => asset($destinationPathlarge. '/'.$fileName190),
])->save();
I hope it helps :)