.., but the lists that contain the ProductAttributeValues. For a clothing store you will have two entries: - Size - Colour
Наследование: extends DataObject, implements EditableEcommerceObject
 public static function find_or_make($name)
 {
     if ($type = ProductAttributeType::get()->filter("Name:nocase", $name)->first()) {
         return $type;
     }
     $type = new ProductAttributeType();
     $type->Name = $name;
     $type->Label = $name;
     $type->write();
     return $type;
 }
 static function find_or_make($name)
 {
     $name = strtolower($name);
     if ($type = DataObject::get_one('ProductAttributeType', "LOWER(\"Name\") = '{$name}'")) {
         return $type;
     }
     $type = new ProductAttributeType();
     $type->Name = $name;
     $type->Label = $name;
     $type->write();
     return $type;
 }
 function getCMSFields()
 {
     $fields = parent::getCMSFields();
     $values = $fields->fieldByname("Values");
     if ($values instanceof GridField) {
         $values->setModelClass("ColoredProductAttributeValue");
     }
     return $fields;
 }
 /**
  * Generates variations based on selected attributes.
  *
  * @param ProductAttributeType $attributetype
  * @param array $values
  */
 public function generateVariationsFromAttributes(ProductAttributeType $attributetype, array $values)
 {
     //TODO: introduce transactions here, in case objects get half made etc
     //if product has variation attribute types
     if (is_array($values)) {
         //TODO: get values dataobject set
         $avalues = $attributetype->convertArrayToValues($values);
         $existingvariations = $this->owner->Variations();
         if ($existingvariations->exists()) {
             //delete old variation, and create new ones - to prevent modification of exising variations
             foreach ($existingvariations as $oldvariation) {
                 $oldvalues = $oldvariation->AttributeValues();
                 foreach ($avalues as $value) {
                     $newvariation = $oldvariation->duplicate();
                     $newvariation->InternalItemID = $this->owner->InternalItemID . '-' . $newvariation->ID;
                     $newvariation->AttributeValues()->addMany($oldvalues);
                     $newvariation->AttributeValues()->add($value);
                     $newvariation->write();
                     $existingvariations->add($newvariation);
                 }
                 $existingvariations->remove($oldvariation);
                 $oldvariation->AttributeValues()->removeAll();
                 $oldvariation->delete();
                 $oldvariation->destroy();
                 //TODO: check that old variations actually stick around, as they will be needed for past orders etc
             }
         } else {
             foreach ($avalues as $value) {
                 $variation = new ProductVariation();
                 $variation->ProductID = $this->owner->ID;
                 $variation->Price = $this->owner->BasePrice;
                 $variation->write();
                 $variation->InternalItemID = $this->owner->InternalItemID . '-' . $variation->ID;
                 $variation->AttributeValues()->add($value);
                 //TODO: find or create actual value
                 $variation->write();
                 $existingvariations->add($variation);
             }
         }
     }
 }
 /**
  * Adds variations specific fields to the CMS.
  */
 public function updateCMSFields(FieldList $fields)
 {
     $fields->addFieldsToTab('Root.Attributes', array(HeaderField::create('Applicable Attribute Types'), CheckboxSetField::create('StaticAttributeTypes', 'Static Attribute Types', ProductAttributeType::get()->map("ID", "Title")), LiteralField::create('staticattributehelp', '<p>Select any attributes that apply to this product and click Save.</p>'), HeaderField::create('Attributes')));
     foreach ($this->owner->StaticAttributeTypes() as $type) {
         $source = $this->getValuesClosure($type->ID);
         $newValFields = FieldList::create(array(TextField::create('Value', 'Label'), HiddenField::create('TypeID', '', $type->ID)));
         $newValReq = RequiredFields::create('Value');
         $valuesField = HasStaticAttributes_CheckboxSetField::create('StaticAttributeValues-' . $type->ID, $type->Title, $source());
         $valuesField->setValue($this->owner->StaticAttributeValues()->filter('TypeID', $type->ID)->getIDList());
         $valuesField->useAddNew('ProductAttributeValue', $source, $newValFields, $newValReq);
         $fields->addFieldToTab('Root.Attributes', $valuesField);
     }
 }
 /**
  * NOTE: this will break if applied to something that's not a SiteTree subclass.
  * @param DataList|PaginatedList $matches
  * @param array $facet
  * @param int $typeID
  */
 protected function buildAttributeFacet($matches, array &$facet, $typeID)
 {
     $q = $matches instanceof PaginatedList ? $matches->getList()->dataQuery()->query() : $matches->dataQuery()->query();
     if (empty($facet['Label'])) {
         $type = ProductAttributeType::get()->byID($typeID);
         $facet['Label'] = $type->Label;
     }
     $baseTable = $q->getFrom();
     if (is_array($baseTable)) {
         $baseTable = reset($baseTable);
     }
     $q = $q->setSelect(array())->selectField('"ProductAttributeValue"."ID"', 'Value')->selectField('"ProductAttributeValue"."Value"', 'Label')->selectField('count(distinct ' . $baseTable . '."ID")', 'Count')->selectField('"ProductAttributeValue"."Sort"')->addInnerJoin('Product_StaticAttributeValues', $baseTable . '."ID" = "Product_StaticAttributeValues"."ProductID"')->addInnerJoin('ProductAttributeValue', '"Product_StaticAttributeValues"."ProductAttributeValueID" = "ProductAttributeValue"."ID"')->addWhere(sprintf("\"ProductAttributeValue\".\"TypeID\" = '%d'", $typeID))->setOrderBy('"ProductAttributeValue"."Sort"', 'ASC')->setGroupBy('"ProductAttributeValue"."ID"')->execute();
     $facet['Values'] = array();
     foreach ($q as $row) {
         $facet['Values'][$row['Value']] = new ArrayData($row);
     }
 }
 function variationRow(&$obj, $val, $record)
 {
     $obj->write();
     //make sure product is in DB
     //TODO: or find existing variation
     $variation = DataObject::get_one('ProductVariation', "InternalItemID = '{$val}'");
     if (!$variation) {
         $variation = new ProductVariation();
         $variation->InternalItemID = $val;
         $variation->ProductID = $obj->ID;
         //link to product
         $variation->write();
     }
     $varcols = array('->processVariation', '->processVariation1', '->processVariation2', '->processVariation3', '->processVariation4', '->processVariation5', '->processVariation6');
     foreach ($varcols as $col) {
         if (isset($record[$col])) {
             $parts = explode(":", $record[$col]);
             if (count($parts) == 2) {
                 $attributetype = trim($parts[0]);
                 $attributevalues = explode(",", $parts[1]);
                 //get rid of empty values
                 foreach ($attributevalues as $key => $value) {
                     if (!$value || trim($value) == "") {
                         unset($attributevalues[$key]);
                     }
                 }
                 if (count($attributevalues) == 1) {
                     $attributetype = ProductAttributeType::find_or_make($attributetype);
                     foreach ($attributevalues as $key => $value) {
                         $val = trim($value);
                         if ($val != "" && $val != null) {
                             $attributevalues[$key] = $val;
                         }
                         //remove outside spaces from values
                     }
                     $attributetype->addValues($attributevalues);
                     //create and add values to attribute type
                     $obj->VariationAttributes()->add($attributetype);
                     //add variation attribute type to product
                     //TODO: if existing variation, then remove current values
                     //record vairation attribute values (variation1, 2 etc)
                     foreach ($attributetype->convertArrayToValues($attributevalues) as $value) {
                         $variation->AttributeValues()->add($value);
                         break;
                     }
                 }
             }
         }
     }
     //copy db values into variation (InternalItemID, Price, Stock, etc) ...there will be unknowns from extensions.
     $dbfields = $variation->db();
     foreach ($record as $field => $value) {
         if (isset($dbfields[$field])) {
             $variation->{$field} = $value;
         }
     }
     $variation->write();
 }
 function ProductAttributeTypeGetPluralName()
 {
     return Convert::raw2att(ProductAttributeType::get_plural_name());
 }
 function cleanup()
 {
     $sql = "\r\n\t\t\tSelect \"ProductAttributeTypeID\"\r\n\t\t\tFROM \"Product_VariationAttributes\"\r\n\t\t\tWHERE \"ProductID\" = " . $this->owner->ID;
     $data = DB::query($sql);
     $array = $data->keyedColumn();
     if (is_array($array) && count($array)) {
         foreach ($array as $key => $productAttributeTypeID) {
             //attribute type does not exist.
             if (!ProductAttributeType::get()->byID($productAttributeTypeID)) {
                 //delete non-existing combinations of Product_VariationAttributes (where the attribute does not exist)
                 //DB::query("DELETE FROM \"Product_VariationAttributes\" WHERE \"ProductAttributeTypeID\" = $productAttributeTypeID");
                 //non-existing product attribute values.
                 $productAttributeValues = ProductAttributeValue::get()->filter(array("TypeID" => $productAttributeTypeID));
                 if ($productAttributeValues->count()) {
                     foreach ($productAttributeValues as $productAttributeValue) {
                         $productAttributeValue->delete();
                     }
                 }
             }
         }
     }
 }
 private function addvariations()
 {
     $colourObject = ProductAttributeType::get()->where("\"Name\" = 'Colour'")->First();
     if (!$colourObject) {
         $colourObject = new ProductAttributeType();
         $colourObject->Name = "Colour";
         $colourObject->Label = "Colour";
         $colourObject->IsColour = true;
         $colourObject->Sort = 100;
         $colourObject->write();
     }
     if ($colourObject) {
         $redObject = ProductAttributeValue::get()->where("\"Value\" = 'red'")->First();
         if (!$redObject) {
             $redObject = new ProductAttributeValue();
             $redObject->Value = "red";
             $redObject->RGBCode = "ff0000";
             $redObject->ContrastRGBCode = "BFC1C1";
             $redObject->TypeID = $colourObject->ID;
             $redObject->Sort = 100;
             $redObject->write();
         }
         $blueObject = ProductAttributeValue::get()->where("\"Value\" = 'blue'")->First();
         if (!$blueObject) {
             $blueObject = new ProductAttributeValue();
             $blueObject->Value = "blue";
             $blueObject->RGBCode = "0000ff";
             $blueObject->ContrastRGBCode = "BFC1C1";
             $blueObject->TypeID = $colourObject->ID;
             $blueObject->Sort = 110;
             $blueObject->write();
         }
     } else {
         die("COULD NOT CREATE COLOUR OBJECT");
     }
     $sizeObject = ProductAttributeType::get()->filter("Name", 'Size')->First();
     if (!$sizeObject) {
         $sizeObject = new ProductAttributeType();
         $sizeObject->Name = "Size";
         $sizeObject->Label = "Size";
         $sizeObject->Sort = 110;
         $sizeObject->write();
     }
     if ($sizeObject) {
         $smallObject = ProductAttributeValue::get()->where("\"Value\" = 'S'")->First();
         if (!$smallObject) {
             $smallObject = new ProductAttributeValue();
             $smallObject->Value = "S";
             $smallObject->TypeID = $sizeObject->ID;
             $smallObject->Sort = 100;
             $smallObject->write();
         }
         $xtraLargeObject = ProductAttributeValue::get()->where("\"Value\" = 'XL'")->First();
         if (!$xtraLargeObject) {
             $xtraLargeObject = new ProductAttributeValue();
             $xtraLargeObject->Value = "XL";
             $xtraLargeObject->TypeID = $sizeObject->ID;
             $xtraLargeObject->Sort = 110;
             $xtraLargeObject->write();
         }
     } else {
         die("COULD NOT CREATE SIZE OBJECT");
     }
     $products = Product::get()->where("ClassName = 'Product'")->sort("RAND()")->limit(2);
     $this->addExamplePages(1, "products with variations (size, colour, etc...)", $products);
     if ($products->count() && $colourObject && $sizeObject) {
         $variationCombos = array(array("Size" => $xtraLargeObject, "Colour" => $redObject), array("Size" => $xtraLargeObject, "Colour" => $blueObject), array("Size" => $smallObject, "Colour" => $redObject), array("Size" => $smallObject, "Colour" => $blueObject));
         foreach ($products as $product) {
             $existingAttributeTypes = $product->VariationAttributes();
             $existingAttributeTypes->add($sizeObject);
             $existingAttributeTypes->add($colourObject);
             $this->addToTitle($product, "with variation", false);
             $product->Content .= "<p>On this page you can see two example of how you customers can add variations to their products (form / table)... In a real-life shop you would probably choose one or the other.</p>";
             $product->write();
             $product->Publish('Stage', 'Live');
             $product->flushCache();
             $descriptionOptions = array("", "Per Month", "", "", "Per Year", "This option has limited warranty");
             if (!ProductVariation::get()->where("ProductID  = " . $product->ID)->count()) {
                 foreach ($variationCombos as $variationCombo) {
                     $productVariation = new ProductVariation();
                     $productVariation->ProductID = $product->ID;
                     $productVariation->Price = $product->Price * 2;
                     $productVariation->Description = $descriptionOptions[rand(0, 5)];
                     $productVariation->ImageID = rand(0, 1) ? 0 : $this->getRandomImageID();
                     $productVariation->write();
                     $existingAttributeValues = $productVariation->AttributeValues();
                     $existingAttributeValues->add($variationCombo["Size"]);
                     $existingAttributeValues->add($variationCombo["Colour"]);
                     DB::alteration_message(" Creating variation for " . $product->Title . " // COLOUR " . $variationCombo["Colour"]->Value . " SIZE " . $variationCombo["Size"]->Value, "created");
                 }
             }
         }
     }
 }
 /**
  *
  * @param Int | ProductAttributeType
  *
  * @return DataList of ProductAttributeValues
  */
 function possibleValuesForAttributeType($type)
 {
     if ($type instanceof ProductAttributeType) {
         $typeID = $type->ID;
     } elseif ($type = ProductAttributeType::get()->byID(intval($type))) {
         $typeID = $type->ID;
     } else {
         return null;
     }
     $vals = ProductAttributeValue::get()->where("\"TypeID\" = {$typeID} AND \"ProductVariation\".\"ProductID\" = " . $this->owner->ID . "  AND \"ProductVariation\".\"AllowPurchase\" = 1")->sort(array("ProductAttributeValue.Sort" => "ASC"))->innerJoin("ProductVariation_AttributeValues", "\"ProductAttributeValue\".\"ID\" = \"ProductVariation_AttributeValues\".\"ProductAttributeValueID\"")->innerJoin("ProductVariation", "\"ProductVariation_AttributeValues\".\"ProductVariationID\" = \"ProductVariation\".\"ID\"");
     if ($this->variationFilter) {
         $vals = $vals->filter(array("ProductVariation.ID" => $this->variationFilter));
     }
     return $vals;
 }
 protected function createVariations()
 {
     $this->alterationMessage("================================================ CREATING VARIATIONS ================================================", "show");
     foreach ($this->data as $data) {
         $types = array();
         $values = array();
         $product = $data["Product"];
         $arrayForCreation = array();
         $variationFilter = array();
         $this->alterationMessage("<h1>Working out variations for " . $product->Title . "</h1>");
         //create attribute types for one product
         $this->alterationMessage("....Creating attribute types");
         foreach ($this->Config()->get("attribute_type_field_names") as $fieldKey => $fieldName) {
             $startMessage = "........Checking field {$fieldName}";
             $attributeTypeName = trim($data["Product"]->Title) . "_" . $fieldName;
             $filterArray = array("Name" => $attributeTypeName);
             $type = ProductAttributeType::get()->filter($filterArray)->first();
             if (!$type) {
                 $this->alterationMessage($startMessage . " ... creating new attribute type: " . $attributeTypeName, "created");
                 $type = new ProductAttributeType($filterArray);
                 $type->Label = $attributeTypeName;
                 $type->Sort = $fieldKey;
             } else {
                 $this->alterationMessage($startMessage . " ... \tfound existing attribute type: " . $attributeTypeName);
             }
             $this->addMoreAttributeType($type, $fieldName, $product);
             $type->write();
             $types[$fieldName] = $type;
             $product->VariationAttributes()->add($type);
         }
         //go through each variation to make the values
         $this->alterationMessage("....Creating attribute values");
         foreach ($data["VariationRows"] as $key => $row) {
             //go through each value
             foreach ($this->Config()->get("attribute_type_field_names") as $fieldName) {
                 if (!isset($row["Data"][$fieldName])) {
                     $this->alterationMessage("ERROR; {$fieldName} not set at all....", "deleted");
                     continue;
                 } elseif (!trim($row["Data"][$fieldName])) {
                     $this->alterationMessage("skipping {$fieldName} as there are no entries...");
                     continue;
                 }
                 $startMessage = "........Checking field {$fieldName}";
                 //create attribute value
                 $attributeValueName = $row["Data"][$fieldName];
                 $filterArray = array("Code" => $attributeValueName, "TypeID" => $types[$fieldName]->ID);
                 $value = ProductAttributeValue::get()->filter($filterArray)->first();
                 if (!$value) {
                     $this->alterationMessage($startMessage . "............creating new attribute value:  <strong>" . $attributeValueName . "</strong> for " . $types[$fieldName]->Name, "created");
                     $value = ProductAttributeValue::create($filterArray);
                     $value->Code = $attributeValueName;
                     $value->Value = $attributeValueName;
                 } else {
                     $this->alterationMessage($startMessage . "............found existing attribute value: <strong>" . $attributeValueName . "</strong> for " . $types[$fieldName]->Name);
                 }
                 $this->addMoreAttributeType($value, $types[$fieldName], $product);
                 $value->write();
                 $values[$fieldName] = $value;
                 //add at arrays for creation...
                 if (!isset($arrayForCreation[$types[$fieldName]->ID])) {
                     $arrayForCreation[$types[$fieldName]->ID] = array();
                 }
                 $arrayForCreation[$types[$fieldName]->ID][] = $value->ID;
                 if (!isset($variationFilters[$key])) {
                     $variationFilters[$key] = array();
                 }
                 $variationFilters[$key][$types[$fieldName]->ID] = $value->ID;
             }
         }
         //remove attribute types without values... (i.e. product only has size of colour)
         foreach ($product->VariationAttributes() as $productTypeToBeDeleted) {
             if ($productTypeToBeDeleted->Values()->count() == 0) {
                 $this->alterationMessage("....deleting attribute type with no values: " . $productTypeToBeDeleted->Title);
                 $product->VariationAttributes()->remove($productTypeToBeDeleted);
             }
         }
         $this->alterationMessage("....Creating Variations ///");
         //$this->alterationMessage("....Creating Variations From: ".print_r(array_walk($arrayForCreation, array($this, 'implodeWalk'))));
         //generate variations
         $variationAttributeValuesPerVariation = array();
         foreach ($arrayForCreation as $typeID => $variationEntry) {
             foreach ($variationEntry as $positionOfVariation => $attributeValueID) {
                 $variationAttributeValuesPerVariation[$positionOfVariation][$typeID] = $attributeValueID;
             }
         }
         foreach ($variationAttributeValuesPerVariation as $variationAttributes) {
             $variation = $product->getVariationByAttributes($variationAttributes);
             if ($variation instanceof ProductVariation) {
                 $this->alterationMessage(".... Variation " . $variation->FullName . " Already Exists ///");
             } else {
                 //2. if not, create variation with attributes
                 $className = $product->getClassNameOfVariations();
                 $newVariation = new $className(array('ProductID' => $product->ID, 'Price' => $product->Price));
                 $newVariation->setSaveParentProduct(false);
                 $newVariation->write();
                 $newVariation->AttributeValues()->addMany($variationAttributes);
                 $this->alterationMessage(".... Variation " . $newVariation->FullName . " created ///", "created");
             }
         }
         //find variations and add to VariationsRows
         foreach ($data["VariationRows"] as $key => $row) {
             $variation = $product->getVariationByAttributes($variationFilters[$key]);
             if ($variation instanceof ProductVariation) {
                 $this->alterationMessage("........Created variation, " . $variation->getTitle());
                 $this->data[$product->ID]["VariationRows"][$key]["Variation"] = $variation;
             } else {
                 $this->alterationMessage("........Could not find variation", "deleted");
             }
         }
     }
     $this->alterationMessage("================================================", "show");
 }