First of all i would suggest you to go thru database and eloquent sections of documentation. The naming concept is actually pretty easy with laravel. You need posts and pictures tables and one many to many table picture_photo. ( note that table names combined as singular and alphabetical order ). In this table you need two columns photo_id and post_id. Both singular.
I assume you already have both models. In each model you need related models has_many_and_belongs_to funciton
Class post extends Eloquent { ....... ...... public function photos (){ return $ this-> has_many_and_belongs_to("Photo"); } ....... ....... }
And same for photos if you would like to access posts related to each photo
Uploading and saving is totally different story. But i think you should go thru documentation little bit more to understand laravel's MVC structure and relations.
Edit: sorry for bad indentation, trying to post with my phone
Thank you for the answer, I have create the model Picture and the relations like this: Picture Model:
<?php
class Picture extends Eloquent{
protected $table = 'pictures';
protected $fillable = array('path');
public function product()
{
return $this->belongsToMany('Product','products_pictures');
}
}
Product Model:
<?php
class Product extends Eloquent {
public function picture()
{
return $this->belongsToMany('Picture','products_pictures');
}
}
But when I try to save the path to the path field in my pictures table 'path' field I get undifined save() method error.
Here is the Product controller:
public function postCreate(){
$validator = Validator::make(Input::all(), Product::$rules);
//Validation for product,
//if passes create a new product obj and save it on db.
if($validator->passes()){
//Create the new product and store it's details
$product = new Product;
$product->title = Input::get('title');
$product->srtdescription = Input::get('srtdescription');
$product->description = Input::get('description');
$product->price = Input::get('price');
$product->save();
//Create new picture,manipulate with Image Facade,store and sync with product.
$image = new Picture;
$image = Input::file('image');
$filename=date('Y-m-d-h-i-s').".".$image->getClientOriginalName();
$path = public_path('img/products/' . $filename);
Image::make($image->getRealPath())->resize(468, 249)->save($path);
$image->path->'img/products'.$filename;
$image->save();
//Return to products index with success message.
return Redirect::route('admin_products_index')
->with('message','Product Created');
}
//If validation fails return errors, with input.
return Redirect::route('admin_new_product')
->with('message','Something Went Wrong')
->withErrors($validator)
->WithInput();
}
What am I doing wrong? I don't understand, I create a new Picture instance and want to save the picture's path in my path field inside the pictures table.
P.S - I've created the validator, I didn't post it inside my model to save some space and make the code easier to read. Thank you
Hello everyone, after a long night of debugging and a couple cups of coffee I managed to create the system I wanted to link products with posts and create an upload area with thumbnails preview: Here is the solution in case someone else bump into this. I create 2 database tables, one called pictures and one called product_picture to link the picture with the product.
#Database Here is my pictures table Schema:
CREATE TABLE IF NOT EXISTS `pictures` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`path` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`created_at` timestamp NOT NULL,
`updated_at` timestamp NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=35 ;
Here is my picture_product table Schema:
-- Table structure for table `picture_product`
--
CREATE TABLE IF NOT EXISTS `picture_product` (
`product_id` int(11) unsigned DEFAULT NULL,
`picture_id` int(11) unsigned DEFAULT NULL,
KEY `picture_product_id` (`product_id`),
KEY `picture_picture_id` (`picture_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `picture_product`
--
ALTER TABLE `picture_product`
ADD CONSTRAINT `picture_picture_id` FOREIGN KEY (`picture_id`) REFERENCES `pictures` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `picture_product_id` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
#Models
Picture.php Model
<?php
class Picture extends \Eloquent {
protected $fillable = array('path');
public function product()
{
return $this->belongsToMany('Product');
}
}
Product.php Model
<?php
class Product extends Eloquent {
public function picture()
{
return $this->belongsToMany('Picture');
}
}
#Controller ProductsController.php
public function upload(){
//This code will run after saving instance of Product class,because we need to create the product id first.
$files = Input::file('images');
foreach($files as $file) {
$picture = new Picture;
$extension = $file->getClientOriginalExtension();
//Creating sha1 version of the filename in case of conflicts
$sha1 = sha1($file->getClientOriginalName());
$filename=date('Y-m-d-h-i-s').".".$sha1.".".$extension;
$path = public_path('img/products/' . $filename);
// Using Intervention/image package here to resize the pictures
Image::make($file->getRealPath())->resize(468, 249)->save($path);
$picture->path='img/products/' . $filename;
$picture->save();
$product->picture()->attach($picture->id);
}
}
#Views Create Product View. I used this package to create a nice looking input with images previews,most people prefer dropzone ,but it wasn't working for me.
{{Form::label('image', 'Choose images')}}
{{ Form::file('images[]', array('multiple'=>'true','id'=>'image-input','class'=>'file')) }}
Hope this will help someone, and I want to thank SerdarSanri for replying to this thread.
instead of
$product->picture()->attach($picture->id);
you can also use
$product->picture()->save($picture);
as well.
http://laravel.com/docs/4.2/eloquent#inserting-related-models
also you can collect all images in an array and after foreach.. loop
$product->picture()->saveMany($pictures_array);
and one more thing. If you have ability to edit images ( add/remove ) to single product, you may need to use sync method which automatically synchronizes picture_ids with pivot table. I would change the functionality to upload images with ajax and return picture id and just hold them in a array field like picture_ids[]. This also will help you to pick a picture already uploaded. After form submit, in your controller, instead of uploading each picture, which may end up with script timeout if you have few big pictures uploading, you can just use
<input type="hidden" name="picture_ids[]" value='2'>
<input type="hidden" name="picture_ids[]" value='5'>
<input type="hidden" name="picture_ids[]" value='6'>
and in controller class
$images = Input::get("picture_ids" , array() );
$product->pictures()->sync($images);
Laravel will automatically delete removed old images and attach new images if any to the pivot table.
Thank you for the answer, I'm aware of the sync method and what it does.
This is upto saving the the images for related product. Now what i was hoping to see was, how can we access the images related to products when we click the product name. Can you please provide its tutorial.
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community