I modified the schema a bit and came up with a decent solution. It seems confusing, but it's actually very simple.
Each type of property should have it's own table, in this case, size and material. This will make adding additional types of properties very easy as all you have to do is create the table and the model, and you'll be able to start utilizing it right away with no additional changes to code.
class Size extends Eloquent {
public function properties()
{
return $this->morphMany('Property', 'imageable');
}
}
class Material extends Eloquent {
public function properties()
{
return $this->morphMany('Property', 'imageable');
}
}
To bring all the properties together and make them easier to work with, I created a polymorphic table called properties
, which will store the id of the property itself in its table and the class it belongs to, Size
, or Material
.
class CreatePropertiesTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('properties', function($table)
{
$table->increments('id');
$table->integer('imageable_id');
$table->string('imageable_type');
});
}
}
This table will serve 2 purposes, it will obviously act as the table that's managing our polymorphic relations with the Size
and Material
models, and it will be a part of a many-to-many relationship with the products table (a product can have many properties and a property can belong to many products). Here's the model for that table.
class Property extends Eloquent {
public function imageable()
{
return $this->morphTo();
}
public function products()
{
return $this->belongsToMany('Product');
}
}
Finally, to finish our Product/Property relation, we will have the products
table.
class CreateProductTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function($table)
{
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
}
And the Product
model...
class Product extends Eloquent {
public function properties()
{
return $this->belongsToMany('Property');
}
}
And lastly, the table for the Product/Property many-to-many relationship...
class CreatePropertyProductTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('product_property', function($table)
{
$table->increments('id');
$table->integer('product_id');
$table->integer('property_id');
});
}
}
Now with that in mind, it's become extremely easy to answer your original question. To get sizes, just use the Size
model...
$sizes = Size::all()->lists('id', 'name');
and to get them into a select list, when you create your view, pass the variable along in your controller or route
return View::make('some.view')->with('sizes', $sizes);
And in the view
{{ Form::select('size', $sizes, Input::old('size')) }}
To get all the properties for a certain product, that's fairly easy too...
$product = Product::find(1);
foreach($product->properties as $property) {
$property = $property->imageable;
$class = get_class($property);
echo $class;
echo ': ';
echo $property->name;
echo "<br />";
}
You will probably eventually want to limit your sizes available (or other properties, Color/Material etc...) based on what product is selected, in which case, I suggest adding an additional table for managing those, which would have a row for each possible product/property combo. So for example, a product_size
table which would have a row for each possible product/size combo. Then query that relationship when filling out your select values $sizes = Product::find(1)->possibleSizes;