Creating Configurable product programmatically in magento - php

I am trying to create configurable product with the attributes color and size from simple product collection.
To achieve this, I created a custom attribute named configurable_sku for respective simple products and filled with common SKU. Using this SKU we can group to create a configurable product.
I got collection from $product_sku_collection['sku'] like below,
...
array (size=387)
0 =>
array (size=2)
'conf' => string '753315' (length=6)
'simpleprodcollection' =>
array (size=1)
0 =>
array (size=10)
...
1 =>
array (size=2)
'conf' => string '753319' (length=6)
'simpleprodcollection' =>
array (size=1)
0 =>
array (size=10)
...
Below is the php script which i tried so far.
<?php
set_time_limit(0);
error_reporting(E_ALL | E_STRICT);
error_reporting(1);
ini_set('display_errors', 1);
define('D_S', DIRECTORY_SEPARATOR);
require_once 'app/Mage.php';
umask(0);
Mage::app();
if (function_exists('d') === false) {
function d($data, $die = 0, $z = 1, $msg = 1) {
echo"<br/><pre style='padding:2px 5px;background: none repeat scroll 0 0 #E04E19;clear: both;color: #FFFFFF;float: left;font-family: Times New Roman;font-style: italic;font-weight: bold;text-align: left;'>";
if ($z == 1)
Zend_Debug::dump($data);
else if ($z == 2)
var_dump($data);
else
print_r($data);
echo"</pre>";
if ($d == 1)
die();
}
}
function get_attribute_id($option, $type) {
$attributeId = Mage::getResourceModel('eav/entity_attribute')->getIdByCode('catalog_product', $type);
$attribute = Mage::getModel('catalog/resource_eav_attribute')->load($attributeId);
$attributeOptions = $attribute->getSource()->getAllOptions();
foreach ($attributeOptions as $opts_arr) {
if (strtoupper($opts_arr['label']) == strtoupper($option)) {
return $opts_arr['value'];
}
}
return FALSE;
}
$_simple_products = array();
function attributeValueExists($arg_attribute, $arg_value) {
$attribute_model = Mage::getModel('eav/entity_attribute');
$attribute_options_model = Mage::getModel('eav/entity_attribute_source_table');
$attribute_code = $attribute_model->getIdByCode('catalog__simple_product', $arg_attribute);
$attribute = $attribute_model->load($attribute_code);
$attribute_table = $attribute_options_model->setAttribute($attribute);
$options = $attribute_options_model->getAllOptions(false);
foreach ($options as $option) {
if ($option['label'] == $arg_value) {
return $option['value'];
}
}
return false;
}
//$_product = Mage::getModel('catalog/product')->load(46);
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('*');
// d($collection->getData()); exit;
$in = 0;
$product_sku_collection = array();
$product_dummy_collection = array();
foreach ($collection->getData() as $val) {
$product_dummy_collection[$in] = $val;
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToFilter('confiugrable_sku', array('eq', $val['sku']));
if (count($collection->getData()) > 0) {
$product_sku_collection['sku'][$in]['conf'] = $val['sku'];
$product_sku_collection['sku'][$in]['simpleprodcollection'] = $collection->getData();
$in++;
}
}
$color_attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 92);
foreach ($color_attribute->getSource()->getAllOptions(true, true) as $option) {
$attributeArray[$option['value']] = $option['label'];
}
//d($attributeArray); exit;
$color_array = array();
$index = 0;
foreach ($attributeArray as $value) {
$value_index = get_attribute_id($value, 'color');
if ($value != '') {
$color_array[$index] = array(
'value_index' => $value_index,
'label' => $value,
'is_percent' => 0,
'pricing_value' => '0',
'attribute_id' => '92'
);
$index++;
}
}
//d($color_array); exit;
$size_attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 136);
foreach ($size_attribute->getSource()->getAllOptions(true, true) as $option) {
$sattributeArray[$option['value']] = $option['label'];
}
//d($attributeArray); exit;
$size_array = array();
$index = 0;
foreach ($sattributeArray as $value) {
$value_index = get_attribute_id($value, 'size');
if ($value != '') {
$size_array[$index] = array(
'value_index' => $value_index,
'label' => $value,
'is_percent' => 0,
'pricing_value' => '0',
'attribute_id' => '92'
);
$index++;
}
}
//d($size_array); exit;
// exit;
$cProduct = Mage::getModel('catalog/product');
$model = Mage::getModel('catalog/product');
$setConfigurableAttributesData = array(
'0' => array('id' => NULL, 'label' => 'Color', 'position' => NULL,
'values' => $color_array,
'attribute_id' => 92, 'attribute_code' => 'color', 'frontend_label' => 'Color',
'html_id' => 'config_super_product__attribute_0'
),
'1' => array('id' => NULL, 'label' => 'Clothing Size', 'position' => NULL,
'values' => $size_array,
'attribute_id' => 136, 'attribute_code' => 'size', 'frontend_label' => 'Clothing Size',
'html_id' => 'config_super_product__attribute_1')
);
//d(($product_sku_collection['sku'])); exit;
$index = 1;
foreach ($product_sku_collection['sku'] as $key => $value) {
$main_product_data = $model->load($value['simpleprodcollection']['0']['entity_id']);
$main_pd_name = $main_product_data->getData('name');
$setConfigurableProductsData=array();
//d($value['simpleprodcollection']['0']['entity_id']);
foreach ($value['simpleprodcollection'] as $v) {
$clab = Mage::getModel('catalog/product')->load($v['entity_id'])->getAttributeText('color');
$cvalue_index = Mage::getResourceModel('catalog/product')->getAttributeRawValue($v['entity_id'], 'color');
$slab = Mage::getModel('catalog/product')->load($v['entity_id'])->getAttributeText('size');
$svalue_index = Mage::getResourceModel('catalog/product')->getAttributeRawValue($v['entity_id'], 'size');
$setConfigurableProductsData = array(
$v['entity_id'] =>
array('0' =>
array('attribute_id' => '92', 'label' => $clab, 'value_index' => $cvalue_index, 'is_percent' => 0, 'pricing_value' => ''),
'1' =>
array('attribute_id' => '136', 'label' => $slab, 'value_index' => $svalue_index, 'is_percent' => 0, 'pricing_value' => '')
)
);
//d($setConfigurableProductsData);
}
$cProduct
->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE)
->setTaxClassId(5)
->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
->setWebsiteIds(array(1))
->setAttributeSetId(4) // You can determine this another way if you need to.
->setSku("C" . $main_product_data->getData('confiugrable_sku'))
->setName($main_product_data->getData('name'))
->setQty(25)
->setPlayer($main_product_data->getData('player'))
->setBrand($main_product_data->getData('brand'))
->setStyle($main_product_data->getData('style'))
->setShortDescription($main_product_data->getData('short_description'))
->setDescription($main_product_data->getData('description'))
->setPrice($main_product_data->getData('price'));
$cProduct->setStockData(array(
'use_config_manage_stock' => 1,
'is_in_stock' => 1,
'is_salable' => 1,
));
$cProduct->setConfigurableProductsData($setConfigurableProductsData);
$cProduct->setConfigurableAttributesData($setConfigurableAttributesData);
$cProduct->setCanSaveConfigurableAttributes(1);
try {
$cProduct->save();
//$productId = $cProduct->getId();
echo $index.") ".$cProduct->getId() . "====>" . $main_pd_name . " added\n";
} catch (Exception $e) {
echo "$main_pd_name not added\n";
echo "exception:$e";
}
$index++;
}
//****************-----------------*****************//
?>
When I run this script, it has to insert 387 configurable products with their respective simple product. But loop runs one time and stops executing, It inserts only one configurable product with their associated simple product but it has to insert all 387 configurable products.
Where have I gone wrong in this. I checked all the way to find it but could not.
Kindly give some advice on this

Finally i found it, we need to use below code inside for loop
$cProduct->save();
$cProduct->unsetData();
To make magento recognize your data as a new model again, you simply need to unset the model id

Mage::getModel('catalog/product'); this actually queries Magento registry and fetch a cached object of that model type, this style of reusing objects is known as Singleton and Magento is known for that. In cases of loops and continuous need for a new unique object, use the standard constructor call of that model. For example in case of products:
$cProduct = new Mage_Catalog_Model_Product();

Related

PHP how to get value from multidimensional array?

I have an array in a class and want to obtain the 'Apple' key value ('iPhone').
I assume a for each loop needs to be used.
How would I go about doing this?
UPDATE: I also need to specify the customerType and productType key values.
class Products {
public function products_list() {
$customerType = 'national';
$productType = 'phones';
$phoneType = 'Apple';
$productsArr = array();
$productsArr[] = array(
'customerType' => 'national',
'productType' => array(
'phones' => array(
'Apple' => 'iPhone',
'Sony' => 'Xperia',
'Samsung' => 'Galaxy'
),
'cases' => array(
'leather' => 'black',
'plastic' => 'red',
),
),
'international' => array(
'phones' => array(
'BlackBerry' => 'One',
'Google' => 'Pixel',
'Samsung' => 'Note'
),
'cases' => array(
'leather' => 'blue',
'plastic' => 'green'
),
)
);
}
}
I have created a function that you can more or less give it any product and it will return the key and value from the array
<?php
class Products
{
public function products_list()
{
$customerType = 'national';
$productType = 'phones';
$phoneType = 'Apple';
$productsArr[] = array(
'customerType' => 'national', 'productType' => array(
'phones' => array(
'Apple' => 'iPhone',
'Sony' => 'Xperia',
'Samsung' => 'Galaxy'
),
'cases' => array(
'leather' => 'black',
'plastic' => 'red',
),
),
'international' => array(
'phones' => array(
'BlackBerry' => 'One',
'Google' => 'Pixel',
'Samsung' => 'Note'
),
'cases' => array(
'leather' => 'blue',
'plastic' => 'green'
),
)
);
echo $this->get_value($phoneType, $productsArr) .'<br>';
echo $this->get_value($customerType, $productsArr) .'<br>';
echo $this->get_value($productType, $productsArr) .'<br>';
}
function get_value($product, array $products)
{
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($products), RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $key => $value) {
if (is_string($value) && ($key == $product)) {
return 'key ->' . $key .' value ->'.$value;
}
}
return "";
}
}
$phone_products = new Products();
$phone_products->products_list();
To use it within the class just call
$this->get_value($phoneType, $productsArr);
from without the class call
$phone_products = new Products();
echo ($phone_products->get_value($phoneType, $productsArr));
//output: key ->Apple value ->iPhone
NB: $phoneType, $productsArr will either be defined the methods they are being used in or passed from other methods or define global variables within the class.
If you want single entry:
echo $productsArr[0]['productType']['phones']['Apple']."<br />";
If there are multiple data, you can use foreach:
foreach ($productsArr as $prod){
echo $prod['productType']['phones']['Apple']."<br />";
}
just try
foreach($productsArr[0]['productType']['phones'] as $phones){
echo $phones[$phoneType]; }
foreach($productsArr as $key1 => $data1 ){
if(is_array($data1))
foreach($data1 as $key2 => $data2 ){
if(is_array($data2))
foreach($data2 as $key3 => $data3 ){
if(array_key_exists('Apple', $data3)) {
echo $data3['Apple'] ."\n";
}
}
}
}

Search values on multidimensional array then display the result

I'm trying to retrieve the values on multidimensional arrays using a search like function.
$rows = array(
array(
'Name'=>'City of God',
'Year'=>'2002',
'Rating'=>'10'
),
array(
'Name'=>'The Great Escape',
'Year'=>'1963',
'Rating'=>'9'
),
array(
'Name'=>'Dune',
'Year'=>'1984',
'Rating'=>'6'
),
array(
'Name'=>'Superbabies: Baby Geniuses 2',
'Year'=>'2004',
'Rating'=>'1'
)
);
So for example, if you want to search the array with a value of Name with 'City of God' and Year with '1963' the expected output should be like this
$rows = array(
array(
'Name'=>'City of God',
'Year'=>'2002',
'Rating'=>'10'
),
array(
'Name'=>'The Great Escape',
'Year'=>'1963',
'Rating'=>'9'
),
);
Currently, the function I am using is this
function multiSearch(array $array, array $pairs)
{
$found = array();
foreach ($array as $aKey => $aVal) {
$coincidences = 0;
foreach ($pairs as $pKey => $pVal) {
if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal) {
$coincidences++;
}
}
if ($coincidences == count($pairs)) {
$found[$aKey] = $aVal;
}
}
return $found;
}
However, using this function only capable of retrieving data of the same array key. So for example if I search the value of Name of 'City of God'
$x = multiSearch($rows, array('Name' => 'City of God')
This will display the correct output like this
$rows = array(
array(
'Name'=>'City of God',
'Year'=>'2002',
'Rating'=>'10'
),
);
Unfortunately, if you try to use, 'Name' => 'City of God' and 'Year' => '1963'
It will not display any output. I'm stuck on figuring out on displaying the correct output, any ideas would be appreciated
Try this :
$datas = array(
array(
'Name'=>'City of God',
'Year'=>'2002',
'Rating'=>'10'
),
array(
'Name'=>'The Great Escape',
'Year'=>'1963',
'Rating'=>'9'
),
array(
'Name'=>'Dune',
'Year'=>'1984',
'Rating'=>'6'
),
array(
'Name'=>'Superbabies: Baby Geniuses 2',
'Year'=>'2004',
'Rating'=>'1'
)
);
$search = array(
'Name' => 'Dune',
'Year' => '2004'
);
$output = array();
foreach ($datas as $key1 => $row) {
foreach ($row as $key2 => $value) {
if($search[$key2] == $value) {
// if(stristr($value, $search[$key2]) !== FALSE) { // if you want to search
$output[] = $datas[$key1];
break;
}
}
}
echo "<pre>"; print_r($output); exit;
Output:
Array
(
[0] => Array
(
[Name] => Dune
[Year] => 1984
[Rating] => 6
)
[1] => Array
(
[Name] => Superbabies: Baby Geniuses 2
[Year] => 2004
[Rating] => 1
)
)
If you need OR, as you mentioned in your question, you then need to see if at least one coincidence happened:
if ($coincidences > 0) {
$found[$aKey] = $aVal;
}
This way, both entries:
$rows = array(
array(
'Name'=>'City of God',
'Year'=>'2002',
'Rating'=>'10'
),
array(
'Name'=>'The Great Escape',
'Year'=>'1963',
'Rating'=>'9'
),
);
will be matched.
Modify the search function to this - works for both the cases mentioned:
function multiSearch($rows, $value) {
$newArr = array();
foreach ($rows as $row) {
foreach ($value as $key => $val) {
if (isset($row[$key]) && $row[$key] == $val) {
$newArr[] = $row;
}
}
}
return $newArr;
}
Calling with one or two values produces the required output -
$x = multiSearch($rows, array('Name' => 'City of God'));
$x = multiSearch($rows, array('Name' => 'City of God', 'Year' => '1963'));
//returns $rows containing this pair
Take a look on my suggestion
function search ($storage, $criteria)
{
return array_filter(
$storage,
function ($row) use ($criteria) {
foreach ($criteria as $key => $value) {
if ($row[$key] === $value) {
return true;
}
}
}
);
}
$result = search($datas, $search);
/**
* $result = [
* 2 => [
* 'Name' => 'Dune'
* 'Year' => '1984'
* 'Rating' => '6'
* ],
* 3 => [
* 'Name' => 'Superbabies: Baby Geniuses 2'
* 'Year' => '2004'
* 'Rating' => '1'
* ]
* ];
*/
what about a recursive call?
function recursiveInArray ($needle, $array) {
$status = false;
foreach($array as $value) {
if(is_array($value)) {
recursiveInArray($needle, $value);
} else {
$status = ($needle == $value);
}
}
return $status;
}
i know its abstract, but should help you working with multi dimensional searching

Populating database field with multiple value

I am working on populating the database tables. The table have fields which some of them are enum.
Consider a user which have a field status , whose values can be active, inactive etc. Assume we can modify the configuration values and running the script the data can be populated accordingly.
Let us represent the user table whose status field as
'status' => array(
'active' => 3,
'inactive',
'deleted',
),
In this case assume we need to create 3 users with status , active. 1 user with status inactive and 1 with deleted.
The table may be having more enum fields. So the config can expand. Depending on the configuration and fields the values will be multiples.
Consider the below example.
Eg :
$config = array(
'table1name' => array(
'field1' => array(
'active' => 3,
'inactive',
'deleted',
),
'field2' => array(
'admin',
'user',
'editor'
),
....,
'more-fields' => array(
'more-values',
)
),
'table2name' => array(
'field1' => array(
'active',
'inactive',
'deleted',
),
)
);
In this case there need to populate table1 whose field field1 with active, inactive, deleted and roles with admin, user, editor etc. ( The active, inactive etc are provided just for example. It can be just values. )
The idea is to generate more users depending on the count if any provided.
Eg :
'status' => array(
'active' => 10,
'inactive' => 2,
'deleted' => 3,
),
'roles' => array(
'admin' => 2,
'user',
'editor'
)
....,
'more-fields' => array(
'more-values',
)
So that there will be
10 * 4 => active users (10 * 2 active admin / 10 active user, 10 active editor ) +
2 * 4 => inactive users ( 2 inactive admin , 1 user, 1 editor ) +
3 * 4 => deleted users in total.
I am struggling to build the algorithm for the same.
array(
'status' => array(
'active' => 10,
'inactive' => 2,
'deleted' => 3,
),
'roles' => array(
'admin' => 2,
'user',
'editor'
),
....,
'more-fields' => array(
'more-values',
)
)
// In this example you can see we have not covered the fields of the table when they are more than 1 on save.It looks we need to build the array with values first.
foreach ($config as $table => $fields) {
foreach ($fields as $field => $values ) {
foreach ($values as $key => $statusCount) {
if (is_string($key)) {
$model = new User();
$model->$field = $key;
$model->another = 'value';
$model->save();
} else {
for ($i = 0; $i< $statusCount; $i++) {
$model = new User();
$model->$field = $key;
$model->another = 'value';
$model->save();
}
}
}
}
}
UPDATE :
Changes made according to #the-fourth-bird answer https://stackoverflow.com/a/33354032/487878
Problem is it only look for 2 fields, the fields can be 1 or n.
Are you looking for a setup like this? (Not sure what the fields for the User can be, I used 'role' and 'admin' in this example.)
$fields = array(
'status' => array(
'active' => 10,
'inactive' => 2,
'deleted' => 3,
),
'roles' => array(
'admin',
'user',
'editor'
)
);
$roles = $fields['roles'];
$statuses = $fields['status'];
foreach ($roles as $role) {
foreach ($statuses as $status => $statusCount) {
for ($i = 0; $i< $statusCount; $i++) {
$model = new User();
$model->role = $role;
$model->status = $status;
}
}
}
// Update with dynamic properties
<?php
class table1name {
public function save() {}
}
class table2name {
public function save() {}
}
$config = array(
'table1name' => array(
'field1' => array(
'active' => 3,
'inactive',
'deleted',
),
'field2' => array(
'admin',
'user' => 2,
'editor'
),
'more-fields' => array(
'more-values' => 2,
),
'color' => array(
'blue' => 2,
'red'
),
),
'table2name' => array(
'field1' => array(
'active',
'inactive',
'deleted',
),
)
);
// Adjust data structure
// If the key is a string, turn the key into values for the given multiplier in the same array.
// Then unset the key.
foreach ($config as $table => $fields) {
foreach ($fields as $field => $values ) {
foreach ($values as $key => $statusCount) {
if (is_string($key)) {
for ($i = 0; $i< $statusCount; $i++) {
$config[$table][$field][] = $key;
}
unset($config[$table][$field][(string)$key]);
}
}
}
}
$cartesians = [];
// If you want all the possible combinations for for example the 'table1name', you need a cartesian product. Used the function from this page:
//http://stackoverflow.com/questions/6311779/finding-cartesian-product-with-php-associative-arrays
function cartesian($input) {
$input = array_filter($input);
$result = array(array());
foreach ($input as $key => $values) {
$append = array();
foreach($result as $product) {
foreach($values as $item) {
$product[$key] = $item;
$append[] = $product;
}
}
$result = $append;
}
return $result;
}
// Create the cartesian products for all the keys in the $config array.
foreach ($config as $key => $tables) {
$cartesians[$key] = cartesian($tables);
}
// Loop all the objects created by the cartesian function.
foreach ($cartesians as $objectName => $cartesian) {
foreach($cartesian as $key => $value) {
$model = new $objectName();
$model->$key = $value;
$model->save();
}
}

PHP: merge multidimensional, associative arrays (LEFT JOIN simulation - keep duplicates, keep non-existent elements)

I got two associative, multidimensional arrays $arrayOffered and $arraySold. I would like to merge them under certain conditions:
if value of key 'item' from $arrayOffered exists in $arraySold, both elements should be included in array $result. If for 1 element from $arrayOffered there are 3 elements in $arraySold, I should get also 3 elements in $result.
otherwise, element from $arrayOffered should be added into $result.
One element from $arrayOffered can have >1 equivalents in $arraySold. They should be joined in the way shown below.
Input data:
$arrayOffered = array(
0 => array('item' => 'product_1', 'Category' => 'ABC'),
1 => array('item' => 'product_2', 'Category' => 'DEF')
);
$arraySold = array(
0 => array('item' => 'product_1', 'ItemsSold' => '2', 'ItemsReturned' => 1), //arrays in this array can contain up to 30 elements
1 => array('item' => 'product_1', 'ItemsSold' => '1')
);
Desired result:
$desiredResult = array(
0 => array('item' => 'product_1', 'Category' => 'ABC', 'ItemsSold' => '2', 'ItemsReturned' => 1),
1 => array('item' => 'product_1', 'Category' => 'ABC', 'ItemsSold' => '1'),
2 => array('item' => 'product_2', 'Category' => 'DEF')
);
I got stuck on something like:
$result = array();
foreach ($arrayOffered as $keyOffered => $offeredSubArr)
{
$item = $offeredSubArr['item'];
foreach($arraySold as $keySold => $soldSubArr)
{
if(isset($soldSubArr['item']) && $soldSubArr['item'] == $item)
{
$i = 0;
$test = array_merge($offeredSubArr, $soldSubArr);
$result[$i][] = $test;
$i++;
}
else
{
$result[$i][] = $offeredSubArr;
$i++;
}
}
}
Problem:
- output array isn't formatted the way I wanted
- I know I'm not going in the right direction. Can you please give me a hint?
This is an option, since you have this $arrayOffered as a kind of master file I suggest to build a hash with this array and use later on the foreach look for sold array.
$arrayOffered = array(
0 => array('item' => 'product_1', 'Category' => 'ABC'),
1 => array('item' => 'product_2', 'Category' => 'DEF')
);
$arraySold = array(
0 => array('item' => 'product_1', 'ItemsSold' => '2', 'ItemsReturned' => 1), //arrays in this array can contain up to 30 elements
1 => array('item' => 'product_1', 'ItemsSold' => '1')
);
//Build a hash to get the extra properties
$hashArray = array();
foreach ($arrayOffered as $offered) {
$hashArray[$offered['item']]=$offered;
}
$resultArray = array();
foreach ($arraySold as $sold) {
$hashItem = $hashArray[$sold['item']];
// you dont want this sold flag on your final result
unset($hashItem['sold']);
$resultArray[]=array_merge($hashItem,$sold);
$hashArray[$sold['item']]['sold']= true;
}
//Add all the missing hash items
foreach($hashArray as $hashItem){
if(!isset($hashItem['sold'])){
$resultArray[]=$hashItem;
}
}
print_r($resultArray);
Test sample
http://sandbox.onlinephpfunctions.com/code/f48ceb3deb328088209fbaef4f01d8d4430478db
$result = array();
foreach ($arrayOffered as $keyOffered => $offeredSubArr)
{
$item = $offeredSubArr['item'];
foreach($arraySold as $keySold => $soldSubArr)
{ $i = 0;
if(isset($soldSubArr['item']) && $soldSubArr['item'] == $item)
{
$test = array_merge($offeredSubArr, $soldSubArr);
$result[$i][] = $test;
}
else
{
$result[$i][] = $offeredSubArr;
}
$i++;
}
}
$result = $result[0];
echo '<pre>'; print_r($result); die();
Well i will try to follow your logic although there is simpler solutions.
First of all we will need to search in a multidimentional array thats why we will need the followed function from this so thread
function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
return true;
}
}
return false;
}
Next after small changes:
$i you don't need to make it zero on every loop just once so place it outside
unnecessary [] ($result[$i][]) you don't need the empty brackets no reason to create an extra table in the $i row since what you add there, the $test is already table itself
Adding the last loop coz when sth is not in the second table it will be added in your new table in every loop and as far as i get you don't want that kind of duplicates
We have the following code:
$arrayOffered = array(
0 => array('item' => 'product_1', 'Category' => 'ABC'),
1 => array('item' => 'product_2', 'Category' => 'DEF')
);
$arraySold = array(
0 => array('item' => 'product_1', 'ItemsSold' => '2', 'ItemsReturned' => 1), //arrays in this array can contain up to 30 elements
1 => array('item' => 'product_1', 'ItemsSold' => '1')
);
$i = 0;
$result = array();
foreach ($arrayOffered as $keyOffered => $offeredSubArr)
{
$item = $offeredSubArr['item'];
foreach($arraySold as $keySold => $soldSubArr)
{
if(isset($soldSubArr['item']) && $soldSubArr['item'] == $item)
{
$test = array_merge($offeredSubArr, $soldSubArr);
$result[$i] = $test;
$i++;
}
}
}
foreach ($arrayOffered as $value)
{
if (!in_array_r($value['item'], $result))
{
$result[$i] = $value;
$i++;
}
}
print_r($result);
Which as far as i tested gives the wanted result.

Convert non-nested and bracketed array to nested array

I'm in PHP and I've got an array that looks like this. A single dimension array whose keys are bracketed strings.
array(
'matrix[min_rows]' => '0',
'matrix[max_rows]' => '',
'matrix[col_order][]' => 'col_new_1',
'matrix[cols][col_new_0][type]' => 'text',
'matrix[cols][col_new_1][type]' => 'text',
'matrix[cols][col_new_0][label]' => 'Cell 1',
'matrix[cols][col_new_1][label]' => 'Cell 2',
'matrix[cols][col_new_0][name]' => 'cell_1',
'matrix[cols][col_new_1][name]' => 'cell_2',
'matrix[cols][col_new_0][instructions]' => '',
'matrix[cols][col_new_1][instructions]' => '',
'matrix[cols][col_new_0][width]' => '33%',
'matrix[cols][col_new_1][width]' => '',
'matrix[cols][col_new_0][settings][maxl]' => '',
'matrix[cols][col_new_0][settings][fmt]' => 'none',
'matrix[cols][col_new_0][settings][content]' => 'all',
'matrix[cols][col_new_1][settings][maxl]' => '140',
'matrix[cols][col_new_1][settings][multiline]' => 'y',
'matrix[cols][col_new_1][settings][fmt]' => 'none',
'matrix[cols][col_new_1][settings][content]' => 'all',
)
Is there any easy way to convert that to a normal nested array, ie:
array(
'matrix' => array(
'min_rows' => '0',
'max_rows' => '',
'col_order' => array('col_new_1'),
'cols' => array(
'col_new_0' => array(
'type' => 'text',
'label' => 'Cell 1',
....etc....
This is my current solution, but I was wondering if there's something more native or efficient:
foreach ($decoded_field_type_settings as $key => $value)
{
if (preg_match_all('/\[(.*?)\]/', $key, $matches))
{
$new_key = substr($key, 0, strpos($key, '['));
if ( ! isset($field_type_settings[$new_key]))
{
$field_type_settings[$new_key] = array();
}
$array =& $field_type_settings[$new_key];
$count = count($matches[1]) - 1;
foreach ($matches[1] as $i => $sub_key)
{
if ( ! $sub_key)
{
if ($i < $count)
{
$array[] = array();
}
else
{
$array[] = $value;
}
}
else
{
if ( ! isset($array[$sub_key]))
{
if ($i < $count)
{
$array[$sub_key] = array();
}
else
{
$array[$sub_key] = $value;
}
}
}
if ($i < $count)
{
$array =& $array[$sub_key];
}
}
}
else
{
$field_type_settings[$key] = $value;
}
}
UPDATE: I posted an answer below.
This might work, although it would probably generate some warnings:
$matrix = array();
foreach($arr as $key => $value) {
eval('$' . $key . ' = \'' . $value . '\';');
}
var_dump($matrix);
I think this should do it...
<?php
function convert2dTo3d($source) {
$refs = array();
$output = array();
foreach ($source AS $key => $val) {
$tok = strtok($key, '[]');
$prev_tok = NULL;
while ($tok !== FALSE) {
$this_ref =& $refs[$tok];
if ($prev_tok === NULL)
$output[$tok] =& $this_ref;
else
$refs[$prev_tok][$tok] =& $this_ref;
$prev_tok = $tok;
$tok = strtok('[]');
if ($tok === FALSE)
$refs[$prev_tok] = $val;
}
}
return $output;
}
// Test
$source = array(
'matrix[min_rows]' => '0',
'matrix[max_rows]' => '',
'matrix[col_order][]' => 'col_new_1',
'matrix[cols][col_new_0][type]' => 'text',
'matrix[cols][col_new_1][type]' => 'text',
'matrix[cols][col_new_0][label]' => 'Cell 1',
'matrix[cols][col_new_1][label]' => 'Cell 2',
'matrix[cols][col_new_0][name]' => 'cell_1',
'matrix[cols][col_new_1][name]' => 'cell_2',
'matrix[cols][col_new_0][instructions]' => '',
'matrix[cols][col_new_1][instructions]' => '',
'matrix[cols][col_new_0][width]' => '33%',
'matrix[cols][col_new_1][width]' => '',
'matrix[cols][col_new_0][settings][maxl]' => '',
'matrix[cols][col_new_0][settings][fmt]' => 'none',
'matrix[cols][col_new_0][settings][content]' => 'all',
'matrix[cols][col_new_1][settings][maxl]' => '140',
'matrix[cols][col_new_1][settings][multiline]' => 'y',
'matrix[cols][col_new_1][settings][fmt]' => 'none',
'matrix[cols][col_new_1][settings][content]' => 'all',
);
echo "<pre>";
print_r(convert2dTo3d($source));
echo "</pre>";
It seems that the OP wants, as output, an array declaration which can be parsed directly by PHP. So I suggest to use var_export().
$array = array(
'matrix[min_rows]' => '0',
// ......
// ......
// ......
'matrix[cols][col_new_1][settings][content]' => 'all'
);
$matrix = array();
foreach ($array as $key => $value)
{
// fix missing quotes around array indexes
$key = str_replace(array("[", "]", "['']"), array("['", "']", "[]"), $key);
// fill PHP array
eval('$'.$key.' = $value;');
}
var_export($matrix);
You can make use of a simple, regular expression based parser that creates a multidimensional array based on the information stored in the string per each key:
function parse_flat_matrix(array $flat)
{
$matrix = array();
$varname = 'matrix';
$nameToken = '[a-z0-9_]*';
foreach($flat as $key => $value)
{
$keys = preg_split(sprintf('/(\[%s\])/', $nameToken), $key, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if ($varname !== array_shift($keys))
{
throw new InvalidArgumentException(sprintf('Invalid key %s.', $key));
}
$p =& $matrix;
foreach($keys as $k)
{
$r = preg_match(sprintf('/^\[(%s)\]$/', $nameToken), $k, $kk);
if (!$r)
{
throw new InvalidArgumentException(sprintf('Invalid subkey %s in key %s.', $k, $key));
}
if ('' === $kk[1])
{
$p =& $p[];
}
else
{
$p =& $p[$kk[1]];
}
}
$p = $value;
unset($p);
}
return $matrix;
}
With your example data given, it will create this array:
Array
(
[min_rows] => 0
[max_rows] =>
[col_order] => Array
(
[0] => col_new_1
)
[cols] => Array
(
[col_new_0] => Array
(
[type] => text
[label] => Cell 1
[name] => cell_1
[instructions] =>
[width] => 33%
[settings] => Array
(
[maxl] =>
[fmt] => none
[content] => all
)
)
[col_new_1] => Array
(
[type] => text
[label] => Cell 2
[name] => cell_2
[instructions] =>
[width] =>
[settings] => Array
(
[maxl] => 140
[multiline] => y
[fmt] => none
[content] => all
)
)
)
)
This was the simplest solution, involving no regex parsing:
$original_array = array(
'matrix[min_rows]' => '0',
'matrix[max_rows]' => '',
'matrix[col_order][]' => 'col_new_1',
'matrix[cols][col_new_0][type]' => 'text',
'matrix[cols][col_new_1][type]' => 'text',
'matrix[cols][col_new_0][label]' => 'Cell 1',
'matrix[cols][col_new_1][label]' => 'Cell 2',
'matrix[cols][col_new_0][name]' => 'cell_1',
'matrix[cols][col_new_1][name]' => 'cell_2',
'matrix[cols][col_new_0][instructions]' => '',
'matrix[cols][col_new_1][instructions]' => '',
'matrix[cols][col_new_0][width]' => '33%',
'matrix[cols][col_new_1][width]' => '',
'matrix[cols][col_new_0][settings][maxl]' => '',
'matrix[cols][col_new_0][settings][fmt]' => 'none',
'matrix[cols][col_new_0][settings][content]' => 'all',
'matrix[cols][col_new_1][settings][maxl]' => '140',
'matrix[cols][col_new_1][settings][multiline]' => 'y',
'matrix[cols][col_new_1][settings][fmt]' => 'none',
'matrix[cols][col_new_1][settings][content]' => 'all',
);
$query_string = http_build_query($original_array);
$final_array = array();
parse_str($query_string, $final_array);
var_dump($final_array);

Categories