Related
how can i print the whole multidimensional array by using foreach?
<?php
$shop=array // main array
(
"laptop"=>array
(
"conpaq",
"IBM",
"DELL",
"Lenovo"
),
"printer"=>array
(
"canon",
"Hp"
),
"Tabs"=>array
(
"Hp",
"Dell",
"deny"
)
);
This one is a simple list using recursion, it also have tabs to make it more clear when there's a new array-group.
Please try it and adjust for your code.
$shop = array(
'computers' => array(
'dell' => array(
'i7' => array(
'model1' => 'Model 1',
'model2' => 'Model 2',
),
'i5' => 'Model 1'
),
'hp' => array(
'model1' => 'Model 1'
)
),
'printers' => array(
'Epson' => 'Model 1'
)
);
function printProducts($products, $tabsCount = 0){
$result = ''; $tabs = '';
for($i = 0; $i < $tabsCount; $i++){ $tabs .= ' '; }
foreach($products AS $index=>$product){
if(is_array($product)){
$result .= $tabs.$index.'<br>';
$result .= printProducts($product, $tabsCount+1);
}else{
$result .= $tabs.$product.'<br>';
}
}
return $result;
}
echo printProducts($shop);
Ask if there is something you don't understand.
for 2 levels and without recursion. Recusion would be better but this will work.
foreach($shop as $value) {
if (is_array($value)) {
foreach($shop as $value) {
echo "$value<br />";
}
} else {
echo "$value<br />";
}
}
?>
I'm using a php function to create a user listing of entries with pagination. I need to remove entries without name so I tried this code but it doesn't work: entries without name are not removed.
$listing->entries( $order, $eLimit, $eLimStart, true, array('owner' => $userid, 'name' != null), false, $section);
The opposite works well, with this code I get all entries without name:
$listing->entries( $order, $eLimit, $eLimStart, true, array('owner' => $userid, 'name' => null), false, $section);
The name is stored like this in the DB:
- type: varchar(250)
- interclassement: utf8_general_ci
- Null: Yes
- Default: NULL
I'm using PHP Version 5.3.16.
What am I doing wrong please? Thanks a lot.
** EDIT **
The context: Joomla 2.5.9 and SobiPro 1.08. I use SobiPro API to create the listing:
$listing = SPFactory::Controller('listing');
$listing = new SPListingCtrl();
The function entries looks like this
public function entries( $eOrder, $eLimit = null, $eLimStart = null, $count = false, $conditions = array(), $entriesRecursive = false, $pid = -1 )
{
return $this->getEntries( $eOrder, $eLimit, $eLimStart, $count, $conditions, $entriesRecursive, $pid );
}
The function getEntries looks like this:
/**
* #param string $eOrder
* #param int $eLimit
* #param int $eLimStart
* #return array
*/
public function getEntries( $eOrder, $eLimit = null, $eLimStart = null, $count = false, $conditions = array(), $entriesRecursive = false, $pid = 0 )
{
/* var SPDb $db */
$db =& SPFactory::db();
$eClass = SPLoader::loadModel( 'entry' );
$entries = array();
$eDir = 'asc';
$oPrefix = null;
$conditions = is_array( $conditions ) ? $conditions : array();
/* get the ordering and the direction */
if ( strstr( $eOrder, '.' ) ) {
$eOr = explode( '.', $eOrder );
$eOrder = array_shift( $eOr );
$eDir = implode( '.', $eOr );
}
$pid = $pid ? $pid : SPRequest::sid();
/* if sort by name, then sort by the name field */
if ( $eOrder == 'name' ) {
$eOrder = SPFactory::config()->nameField()->get( 'fid' );
}
if ( $entriesRecursive ) {
$pids = $this->_model->getChilds( 'category', true );
if ( is_array( $pids ) ) {
$pids = array_keys( $pids );
}
$pids[ ] = SPRequest::sid();
$conditions[ 'sprl.pid' ] = $pids;
}
else {
$conditions[ 'sprl.pid' ] = $pid;
}
if ( $pid == -1 ) {
unset( $conditions[ 'sprl.pid' ] );
}
/* sort by field */
if ( strstr( $eOrder, 'field_' ) ) {
static $field = null;
$specificMethod = false;
if ( !$field ) {
try {
$db->select( 'fieldType', 'spdb_field', array( 'nid' => $eOrder, 'section' => Sobi::Section() ) );
$fType = $db->loadResult();
}
catch ( SPException $x ) {
Sobi::Error( $this->name(), SPLang::e( 'CANNOT_DETERMINE_FIELD_TYPE', $x->getMessage() ), SPC::WARNING, 0, __LINE__, __FILE__ );
}
if ( $fType ) {
$field = SPLoader::loadClass( 'opt.fields.' . $fType );
}
}
if ( $field && method_exists( $field, 'sortBy' ) ) {
$table = null;
$oPrefix = null;
$specificMethod = call_user_func_array( array( $field, 'sortBy' ), array( &$table, &$conditions, &$oPrefix, &$eOrder, &$eDir ) );
}
if ( !$specificMethod ) {
$table = $db->join(
array(
array( 'table' => 'spdb_field', 'as' => 'fdef', 'key' => 'fid' ),
array( 'table' => 'spdb_field_data', 'as' => 'fdata', 'key' => 'fid' ),
array( 'table' => 'spdb_object', 'as' => 'spo', 'key' => array( 'fdata.sid', 'spo.id' ) ),
array( 'table' => 'spdb_relations', 'as' => 'sprl', 'key' => array( 'fdata.sid', 'sprl.id' ) ),
)
);
$oPrefix = 'spo.';
$conditions[ 'spo.oType' ] = 'entry';
$conditions[ 'fdef.nid' ] = $eOrder;
// $eOrder = 'baseData.' . $eDir;
$eOrder = 'baseData = "", CONVERT(baseData,UNSIGNED INTEGER).' . $eDir;
}
}
else {
$table = $db->join( array(
array( 'table' => 'spdb_relations', 'as' => 'sprl', 'key' => 'id' ),
array( 'table' => 'spdb_object', 'as' => 'spo', 'key' => 'id' )
) );
$conditions[ 'spo.oType' ] = 'entry';
$eOrder = $eOrder . '.' . $eDir;
$oPrefix = 'spo.';
if ( strstr( $eOrder, 'valid' ) ) {
$eOrder = $oPrefix . $eOrder;
}
}
/* check user permissions for the visibility */
if ( Sobi::My( 'id' ) ) {
$this->userPermissionsQuery( $conditions, $oPrefix );
if( isset( $conditions[ $oPrefix . 'state' ] ) && $conditions[ $oPrefix . 'state' ] ) {
$conditions[ 'sprl.copy' ] = 0;
}
}
else {
$conditions = array_merge( $conditions, array( $oPrefix . 'state' => '1', '#VALID' => $db->valid( $oPrefix . 'validUntil', $oPrefix . 'validSince' ) ) );
$conditions[ 'sprl.copy' ] = '0';
}
try {
$db->select( $oPrefix . 'id', $table, $conditions, $eOrder, $eLimit, $eLimStart, true );
$results = $db->loadResultArray();
}
catch ( SPException $x ) {
Sobi::Error( $this->name(), SPLang::e( 'DB_REPORTS_ERR', $x->getMessage() ), SPC::WARNING, 0, __LINE__, __FILE__ );
}
Sobi::Trigger( $this->name(), 'AfterGetEntries', array( &$results, $count ) );
if ( count( $results ) && !$count ) {
$memLimit = ( int )ini_get( 'memory_limit' ) * 2097152;
foreach ( $results as $i => $sid ) {
// it needs too much memory moving the object creation to the view
//$entries[ $i ] = SPFactory::Entry( $sid );
$entries[ $i ] = $sid;
}
}
if ( $count ) {
return $results;
}
return $entries;
}
Instead of looking for non empty entries, perhaps you could do the opposite and look for entries that have something, like so:
$listing->entries( $order, $eLimit, $eLimStart, true, array('owner' => $userid, 'name' => '%'), false, $section);
This is purely a guess, however, as we would need to see the entries function to see how the various parameters are being handled.
SOLVED - Thanks everyone for your help !
$listing->entries( $order, $eLimit, $eLimStart, true, array('owner' => $userid, '!name' => null ), false, -1);
So my example inputs are
$example_1 = Array (
0 => Array (
'category' => 'body',
'sub-category' => 'intro',
'id' => 'header',
'copy' => 'Hello',
),
1 => Array (
'category' => 'body',
'sub-category' => 'intro',
'id' => 'footer',
'copy' => 'Bye',
),
);
$example_2 = Array (
0 => Array (
'category' => 'body',
'sub-category' => 'intro',
'sub-sub-category' => 'header',
'sub-sub-child-category' => 'left',
'id' => 'title',
'copy' => 'Hello',
),
1 => Array (
'category' => 'body',
'sub-category' => 'intro',
'sub-sub-category' => 'footer',
'sub-sub-child-category' => 'right',
'id' => 'title',
'copy' => 'Bye',
),
);
I want to transform it into
$example_output_1 = Array (
'body' => Array (
'intro' => Array (
'header' => Array (
'title' => 'Hello',
),
'footer' => Array (
'title' => 'Bye',
),
),
),
);
$example_output_2 = Array (
'body' => Array (
'intro' => Array (
'header' => Array (
'left' => Array (
'title' => 'Hello',
),
),
'footer' => Array (
'right' => Array (
'title' => 'Bye',
)
),
),
),
);
Note the depth of the array is dynamic (it is not set - only by the time it hits 'copy' does it indicate the depth of the array).
I am having problems trying to get the recursion correctly. The basic but very rough algorithm I had was to
- Loop through the Row
- Loop through the contents of the Row
- When the index is "copy" then the final value is current value.
- Then build the array
I managed to get it to process for ONLY one row of the array but it was very messy and kinda patchy, so I got a feeling I really need to start from scratch.
Updated: Attached embarrassing Code as requested (don't scream! ;p)
function buildArray($row, $start = true) {
if ($start) {
$result = array();
}
if ( ! is_array($row) ) {
return $row;
}
// Get the first element of the array include its index
$cellValue = null;
$colId = null;
foreach($row AS $index => $value) {
$cellValue = $value;
$colId = $index;
break;
}
// Reduce the array by one
$tempRow = $row;
$temp = array_shift($tempRow);
if ($colId == 'copy') {
$result[$cell] = buildArray($cellValue, $locale, false);
} else {
$result[$cell] = buildArray($tempRow, $locale, false);
}
return $result;
}
Any help will be greatly appreciated.
Should be pretty straightforward:
$originalArray = array(); // <-- should contain your values
$newArray = array();
foreach( $originalArray as $item )
{
$category = $item['category'];
$subcategory = $item['sub-category'];
if ( empty( $newArray[$category] ) )
{
$newArray[$category] = array();
}
if ( empty( $newArray[$category][$subcategory] ) )
{
$newArray[$category][$subcategory] = array();
}
$newArray[$category][$subcategory][$item['id']] = $item['copy'];
}
See it here in action: http://codepad.viper-7.com/9bDiLP
Update: Now that you've specified that you need unlimited recursion, here's a shot at that:
$originalArray = array(); // <-- Your values go here
$newArray = array();
foreach ( $originalArray as $item )
{
$inception = &$newArray; // http://www.imdb.com/title/tt1375666/
foreach ( $item as $key => $val )
{
if ( $key != 'id' )
{
if ( empty($inception[$val]) )
{
$inception[$val] = array();
}
$inception = &$inception[$val];
}
else
{
$inception[ $val ] = $item['copy'];
break;
}
}
}
...and here's the demo: http://codepad.viper-7.com/F9hY7h
This can be solved iteratively, because the recursion would only happen at the tail end of your function. The following code is the simplification. It builds a new layered array while it iterates over the old.
After transforming each each entry it gets merged using array_merge_recursive.
function transform($a)
{
// create new array and keep a reference to it
$b = array(); $cur = &$b;
foreach ($a as $key => $value) {
if ('id' === $key) {
// we're done, add value to the array built so far using id and copy
$cur[$value] = $a['copy'];
break;
} else {
// create one more level
$cur[$value] = array();
// and update the reference
$cur = &$cur[$value];
}
}
// all done
return $b;
}
// $example_2 is your multi-dimensional array
$merged = call_user_func_array('array_merge_recursive',
array_map('transform', $example_2)
);
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);
How can I edit this foreach loop so that I will be able to use strpos to look if q is found in the label ?
The result array will contain those values.
$q may be anna or ann or reas john
<?php
$q = $_GET["q"];
if (!$q) return;
$data = Array(
Array(
'label' => 'anna c13',
'category' => 'Products'
),
Array(
'label' => 'anders andersson',
'category' => 'People'
),
Array(
'label' => 'andreas johnson',
'category' => 'People'
)
);
$result = array();
foreach ($data as $value) {
array_push($result, array(
"label" => $value["label"],
"category" => $value["category"]
));
}
$json = json_encode($result);
echo $json;
?>
This will output every array in $data where $q is somewhere in 'label'.
<?php
if( !isset( $_GET["q"] )) return;
$q = $_GET["q"];
$data = Array(
Array(
'label' => 'anna c13',
'category' => 'Products'
),
Array(
'label' => 'anders andersson',
'category' => 'People'
),
Array(
'label' => 'andreas johnson',
'category' => 'People'
)
);
$result = array();
foreach ($data as $value) {
if( strpos( $value['label'], $q ) !== false ) {
$result[] = $value;
}
}
$json = json_encode($result);
echo $json;
?>
You haven't defined keys for your $data array - so it automatically take the form of:
array(
0=>array(...),
1=>array(...),
2=>array(...)
)
This means that you're using strtolower on an int - so that's probably why it's failing.
foreach ($data as $value) {
if(strpos($value['label'], $q) !== false){
$result[] = $value;
}
}