-
-
Save ValeriiVasyliev/3d44f0687163474cc419a1d7fc9a6ce3 to your computer and use it in GitHub Desktop.
Library to manipulate Prestashop from scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
prestashop-lib — © 2015 Chloé Tigre Rouge <[email protected]> | |
This is licensed under the same terms as Prestashop. | |
PrestaShop library to create products, categories and all sorts of things | |
programmatically by passing arrays around | |
It needs a bootstrapped PrestaShop framework (you can get one by defining | |
_PS_ROOT_DIR_ and by a | |
require_once(_PS_ROOT_DIR_.'config/config.inc.php'); | |
**/ | |
/** this function borrowed from a Gist | |
https://gist.github.com/freekrai/9588315 | |
**/ | |
if (!function_exists('slugify')) | |
{ | |
function slugify($text) | |
{ | |
// replace non letter or digits by - | |
$text = preg_replace('~[^\\pL\d]+~u', '-', $text); | |
// trim | |
$text = trim($text, '-'); | |
// transliterate | |
if (function_exists('iconv')) | |
{ | |
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text); | |
} | |
// lowercase | |
$text = strtolower($text); | |
// remove unwanted characters | |
$text = preg_replace('~[^-\w]+~', '', $text); | |
if (empty($text)) | |
{ | |
return 'n-a'; | |
} | |
return $text; | |
} | |
} | |
if (!function_exists('coalesce')) | |
{ | |
function coalesce() { | |
$args = func_get_args(); | |
foreach ($args as $arg) { | |
if (!empty($arg)) { | |
return $arg; | |
} | |
} | |
return NULL; | |
} | |
} | |
// necessary hack to be able to manipulate data properly | |
class AdminImportController extends AdminImportControllerCore | |
{ | |
public static function copyImg($i,$s,$o,$g = 'products', $r = true) | |
{ | |
return parent::copyImg($i, $s, $o, $g, $r); | |
} | |
} | |
// book-keeping class to map old and new IDs | |
class bookkeeper | |
{ | |
private function __construct() | |
{} | |
private static $instance = null; | |
public static function getInstance() | |
{ | |
if (self::$instance == null) | |
{ | |
self::buildInstance(); | |
} | |
return self::$instance; | |
} | |
private static function buildInstance() | |
{ | |
self::$instance = new bookkeeper(); | |
self::$instance->datastore = array(); | |
if (file_exists('.bookkeeper.srz')) | |
{ | |
self::$instance->datastore = unserialize( | |
file_get_contents('.bookkeeper.srz') ); | |
} | |
} | |
public $datastore; | |
public function persist() | |
{ | |
file_put_contents('.bookkeeper.srz', serialize($this->datastore)); | |
//echo "Persisted to ".dirname(__FILE__)."/.bookkeeper.srz"; | |
} | |
public function reload() | |
{ | |
$i = unserialize(file_get_contents('.bookkeeper.srz')); | |
$this->datastore = $i; | |
} | |
public function reinit($cls = null) | |
{ | |
if ($cls == null) | |
$this->datastore = array(); | |
else | |
$this->datastore[$cls] = null; | |
} | |
public function storekey($cls, $key, $value) | |
{ | |
if (!isset($this->datastore[$cls])) | |
{ | |
$this->datastore[$cls] = array(); | |
} | |
$this->datastore[$cls][$key] = $value; | |
return $this->datastore[$cls][$key]; | |
} | |
public function delkey($cls, $key) | |
{ | |
if (isset($this->datastore[$cls], $this->datastore[$cls][$key])) | |
{ | |
unset($this->datastore[$cls][$key]); | |
} | |
} | |
public function getval($cls, $key) | |
{ | |
if (isset($this->datastore[$cls][$key])) | |
return $this->datastore[$cls][$key]; | |
else | |
return null; | |
} | |
public function getcached($cls, $key, $misscb) | |
{ | |
if (isset($this->datastore[$cls], $this->datastore[$cls][$key])) | |
{ | |
return $this->datastore[$cls][$key]; | |
} | |
return $this->storekey($cls, $key, call_user_func($misscb)); | |
} | |
} | |
// quick lang array | |
function ctr_psvla($text) | |
{ | |
return array( | |
(int)(Configuration::get('PS_LANG_DEFAULT')) => $text | |
); | |
} | |
/** | |
create attribute group | |
**/ | |
function ctr_ps_create_attributegroup($id, $name, $type, $options) | |
{ | |
$g = new AttributeGroup(); | |
$g->name = ctr_psvla($name); | |
$g->public_name = $g->name; | |
$g->group_type = $type; | |
$g->add(); | |
foreach ($options as $o) | |
{ | |
$a = new Attribute(); | |
$a->name = ctr_psvla($o); | |
$a->id_attribute_group = $g->id; | |
$a->add(); | |
} | |
return $g->id; | |
} | |
/** | |
get attribute id by attribute group and text | |
**/ | |
function ctr_ps_get_attribute($attr_grp, $attr_txt) | |
{ | |
$groups = bookkeeper::getInstance()->getcached( | |
'system', 'attributegroups', | |
function(){ | |
return AttributeGroup::getAttributesGroups(Configuration::get('PS_LANG_DEFAULT')); | |
}); | |
$group = null; | |
foreach ($groups as $g) { | |
if (trim($g['name']) == trim($attr_grp)) | |
{ | |
$group = new AttributeGroup($g['id_attribute_group']); | |
break; | |
} | |
} | |
if ($group == null) | |
{ | |
e_("Cannot find group ".$attr_grp); | |
e_("Groups: ".print_r($groups, true)); | |
die(); | |
return; | |
} | |
$attributes = AttributeGroup::getAttributes( | |
Configuration::get('PS_LANG_DEFAULT'), | |
$group->id | |
); | |
$attribute = null; | |
foreach ($attributes as $attr) | |
{ | |
if ($attr['name'] == $attr_txt) | |
{ | |
$attribute = $attr; | |
break; | |
} | |
} | |
return $attribute; | |
} | |
/** | |
add attribute to product, with specific price | |
**/ | |
function ctr_ps_add_attribute_to_product($product_id, $attr_grp, $attr_txt, $opt_price, $ref, | |
$ean13, $is_default) | |
{ | |
$p = new Product($product_id); | |
$attribute = ctr_ps_get_attribute($attr_grp, $attr_txt); | |
if ($attribute == null) | |
{ | |
e_("Cannot find attribute <$attr_txt> in group <$attr_grp>"); | |
return; | |
} | |
// here we have all needed elements so we add the attribute with proper impact | |
$idPAC = $p->addAttribute($opt_price, 0, 0, 0, array(), $ref, $ean13, $is_default); | |
// now we do a dirty database insert :( | |
ctr_ps_add_combination_to_product_attribute($idPAC, $attribute['id_attribute']); | |
return $idPAC; | |
} | |
function ctr_ps_add_combination_to_product_attribute($id_product_attr,$id_attribute) | |
{ | |
return Db::getInstance()->insert('product_attribute_combination', | |
array ( | |
'id_product_attribute' => $id_product_attr, | |
'id_attribute' => $id_attribute | |
)); | |
} | |
function ctr_ps_add_other_option_to_combination($pac_id, $attr_grp, $attr_txt) | |
{ | |
$attribute = ctr_ps_get_attribute($attr_grp, $attr_txt); | |
echo "Adding <$attr_grp>::$attr_txt to Combination $pac_id\n"; | |
return Db::getInstance()->insert('product_attribute_combination', | |
array ( | |
'id_product_attribute' => $pac_id, | |
'id_attribute' => $attribute['id_attribute'] | |
)); | |
} | |
/** | |
create a single prestashop product according to the | |
data passed in the array | |
Return the product ID | |
$parameters: array with the following informations: | |
product_title: array of l7d strings or mere string if only default | |
description: ditto | |
short_description: ditto | |
reference: string | |
ean13: string | |
price: float | |
wholesale_price: float | |
sales_price: float | |
primary_category: int or null | |
tax_rate: float | |
stock_available: int | |
features: dict | |
enabled: boolean | |
images: array of strings pointing to the images | |
$id: if set, update a product by ID rather than setting it | |
(not well supported) | |
**/ | |
function ctr_ps_create_product($parameters,$id=null) | |
{ | |
if ($id!==null) $p = new Product($id); | |
else $p = new Product(); | |
// perform transformations | |
$slug = ctr_psvla(slugify($parameters['product_title'])); | |
if (!is_array($parameters['product_title'])) | |
$parameters['product_title'] = ctr_psvla($parameters['product_title']); | |
if (!is_array($parameters['description'])) | |
$parameters['description'] = ctr_psvla($parameters['description']); | |
if (!is_array($parameters['short_description'])) | |
$parameters['short_description'] = | |
ctr_psvla($parameters['short_description']); | |
// set basic data - pointless repetitive code | |
$p->name = $parameters['product_title']; | |
$p->description = $parameters['description']; | |
$p->description_short = $parameters['short_description']; | |
$p->link_rewrite = $slug; | |
$p->reference = $parameters['reference']; | |
$p->ean13 = $parameters['ean13']; | |
$p->id_category_default = $parameters['primary_category']; | |
$p->category = $parameters['categories']; | |
$p->price = $parameters['price']; | |
$p->wholesale_price = $parameters['wholesale_price']; | |
$p->tax_rate = $parameters['tax_rate']; | |
if ($p->tax_rate == 20) $p->id_tax_rules_group = 1; | |
elseif ($p->tax_rate == 5.5) $p->id_tax_rules_group = 3; | |
elseif ($p->tax_rate == 10) $p->id_tax_rules_group = 2; | |
elseif ($p->tax_rate == 2.1) $p->id_tax_rules_group = 4; | |
$p->tax_name = 'TVA'; | |
$p->weight = $parameters['weight']; | |
$p->visibility = $parameters['enabled']?'both':'none'; | |
$p->available_for_order = $parameters['enabled']; | |
$p->available_date = $parameters['date_available']; | |
$p->active = $parameters['enabled']; | |
// save so we have a product ID | |
//echo "Trying to create product "; | |
//echo print_r($parameters['product_title'],true)."\n"; | |
$p->save(); | |
$id = $p->id; | |
// now add some features to it. | |
// features can be identified by name | |
foreach ($parameters['features'] as $k=>$v) | |
{ | |
$id_feature = Feature::addFeatureImport($k); | |
Product::addFeatureProductImport($id, $id_feature, $v); | |
} | |
// add to categories | |
//echo "Now adding product $id to categories ".join(", ",$parameters['categories'])."\n"; | |
$p->addToCategories($parameters['categories']); | |
// set stock | |
//echo "Now setting stock for product $id to ".$parameters['stock_available']."\n"; | |
StockAvailable::setQuantity($id, 0, $parameters['stock_available'], (int)Configuration::get('PS_SHOP_DEFAULT')); | |
// now add images | |
$cover = false; | |
foreach ($parameters['images'] as $img) | |
{ | |
ctr_ps_addimagetoproduct($id, $img,!$cover); | |
$cover=true; | |
} | |
return $id; | |
} | |
function ctr_ps_addimagetoproduct($id_product, $img, $cover) | |
{ | |
$image = new Image(); | |
$image->id_product = $id_product; | |
$image->legend = ctr_psvla("default caption"); | |
$image->position = Image::getHighestPosition($id_product)+1; | |
$image->cover = $cover; | |
if (($image->validateFields(false, true)) === true && | |
($image->validateFieldsLang(false, true)) === true && $image->add()) | |
{ | |
$image->associateTo(Shop::getShops(true, null, true)); | |
if (!AdminImportController::copyImg( | |
$id_product, $image->id, dirname(__FILE__).'/'.$img, 'products', false)) | |
{ | |
echo "error adding image $img to associate with | |
$id_product and {$image->id}\n"; | |
print_r($image); | |
// $image->delete(); | |
} | |
else | |
{ | |
copy(dirname(__FILE__)."/$img", $image->getPathForCreation().'.jpg'); | |
} | |
} | |
} | |
/** | |
create a single prestashop category. Return its persisted ID | |
parameters: array | |
label: name of the category | |
description: description | |
slug: URLable designation | |
**/ | |
function ctr_ps_create_category($parameters, $parent=null) | |
{ | |
$cat = new Category(); | |
if ($parameters['slug']=='_') | |
{ | |
$cat = new Category(Configuration::get('PS_HOME_CATEGORY')); | |
} | |
else | |
{ | |
if ($parent == null) //it's a new root | |
{ | |
//$cat->is_root_category = 1; | |
$cat->id_parent == Configuration::get('PS_HOME_CATEGORY'); | |
} | |
else { | |
//echo "Forced parent: $parent\n"; | |
$cat->id_parent = $parent; | |
} | |
$cat->link_rewrite = ctr_psvla($parameters['slug']); | |
$cat->name = ctr_psvla($parameters['label']); | |
$cat->description = ctr_psvla($parameters['description']); | |
$cat->save(); | |
} | |
if ($parent == null) //it's a new root | |
{ | |
// Configuration::set('PS_ROOT_CATEGORY', $cat->id); | |
} | |
bookkeeper::getInstance()->storekey('category-mapping', $parameters['original_id'], $cat->id); | |
return $cat->id; | |
} | |
/** | |
create a category tree and return an exhaustive mapping | |
category names => ID | |
Expected format: | |
same as for ctr_ps_create_category with an additional | |
[children] entry allowing recursion | |
**/ | |
function ctr_ps_create_category_tree($tree, $forced_parent=null) | |
{ | |
$firstrun = null; | |
foreach ($tree as $wood) | |
{ | |
$id = ctr_ps_create_category($wood,$forced_parent); | |
if ($firstrun == null) $firstrun = $id; | |
//echo "Created category with ID $id.\n"; | |
if (isset($wood['children'])) | |
{ | |
//echo "Proceeding with ". count($wood['children'])." kids of $id …\n"; | |
ctr_ps_create_category_tree($wood['children'], $id); | |
} | |
else | |
{ | |
//echo "Category $id has no children.\n"; | |
} | |
} | |
echo "Done creating all categories.\n"; | |
return $firstrun; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment