ErrorException [ Notice ]: Undefined variable on an existing variable dynamically built - variables

First of all thanks for your time on my issue.
Second sorry if this is a duplicate, I legit searched for 3 days on and off and didn't find answer to my particular situation.
Visual on the error obtained
This first line transforms an array's values into a string of index(es)
$path = self::extract_path($path);
After extraction $path becomes a string with a format similar to['key1']['key2']
Here I test if one valuable element (ondemand) is found within that Keys string, so far so good.
if( $path !== FALSE && strpos($path, $element) !== FALSE){
$var_dim_str = 'coupon' . $path . '[recurrence]';
As a self-proofing, I hard-coded one of my specific scenario element and it does exist so my issue is not really non-initialization of my variable as most other topic were suggesting.
var_dump($coupon['item']['ondemand']['recurrence']);
My issue lies here, I get "ErrorException [ Notice ]: Undefined variable: coupon[item][ondemand][recurrence]"
$recurrence = $$var_dim_str;
[...]
Here are my var_dump output:
These are my indexes as an array they get extracted to reconstruct the variable's string', I have some variable-dimension arrays that gets called so the dimension depth might not always be of fixed value, hence why I have to dynamically test this.
1- $path, before being extracted
[...]\modules\payment\classes\Helper\Payment.php:290:
array (size=2)
0 => string 'item' (length=4)
1 => string 'ondemand' (length=8)
2- We see here that (['item']['ondemand']['recurrence'] => 3) exists
[...]\modules\payment\classes\Payment\Cart.php:266:
array (size=1)
'item' =>
array (size=3)
'ondemand' =>
array (size=14)
[...]
'recurrence' => string '3' (length=1)
[...]
3- My var_dump above is outputting it properly.
[...]\modules\payment\classes\Payment\Cart.php:270:string '3' (length=1)
**So, my conclusion is that PHP doesn't really appreciate my 'built' variable but there has to be some way to make this logic work... any pointers on this would be really appreciated. **

The issue does lie with $$var_dim_str. What the $$ does is resolve $$variableName to be the variable name contained in $variableName. It basically holds a reference to another variable based on the variable's name. From the PHP site:
A variable variable takes the value of a variable and treats that as the name of a variable. In the above example, hello, can be used as the name of a variable by using two dollar signs. i.e.
So ...
// some variables
$name = 'Ellan' ;
$site = 'Stack Exchange' ;
$tags = 'PHP-7, Variables' ;
// we want $site
$variableName = 'site' ;
echo $$variableName ;
// we want $tags
$variableName = 'tags' ;
echo $$variableName ;
The code above will produce:
Stack Exchange
PHP-7, Variables
When you assign a value to $var_dim_str:
$var_dim_str = 'coupon' . $path . '[recurrence]';
$var_dim_str does not hold the name of a variable. It contains the a string.
Are you sure you want to use $$ in this instance? Maybe you really want to use:
$recurrence = $var_dim_str;

Related

How to get root node in MEL Script?

I have come across an existing piece of code that does this, but I assume there must be a better way. So, I need to get a highest level in mesh node in Autodesk Maya.
// List all mesh objects
string $nodess[] = `ls -type mesh` ;
// Replace existing items on active list with this
select -r $nodess[0] ;
int $i = 1 ;
while ($i < 30) {
// Pick up the tree 30 times
pickWalk -d up ;
$i++ ;
}
// List all selected objects
string $rootNode[] = `ls -sl` ;
// Clear selection
select -cl ;
string $myroot = $rootNode[0] ;
to get the root, just string-split the long name:
global proc string get_root(string $node)
{
string $longname[] = ls("-l", $node);
string $tokens[];
tokenize($longname[0], "|", $tokens);
return $tokens[0];
}
Of course it's much more elegant in Python:
root = cmds.ls(node, l=True)[0].split("|")[0]
You could also re-write the orignal function by calling listRelatives -p until it returns nothing; but the string method is easier
I think this is probably the most direct:
string $roots[] = `ls -assemblies`;
From the Docs:
-assemblies(-as)
List top level transform Dag objects
I understand this topic is a little out of date... However...
Theodox's answer helped me, but for some reason...
root = cmds.ls(node, l=True)[0].split("|")[0]
...didn't give me the exact answer I needed. Instead...
root = cmds.ls(node, l=True)[0].split("|")[1] #<-- Notice this [1]
gave me me the exact answer I needed. Apparently, [0] provides a blank space in my scene, because the array is listed as...
[u'',u'the_Item_I_Need',u'etc1',u'etc2']
Just a helpful hint if someone is having an issue!!

How to convert a list of attribute-value pairs into a flat table whose columns are attributes

I'm trying to convert a csv file containing 3 columns (ATTRIBUTE_NAME,ATTRIBUTE_VALUE,ID) into a flat table whose each row is (ID,Attribute1,Attribute2,Attribute3,....). The samples of such tables are provided at the end.
Either Python, Perl or SQL is fine. Thank you very much and I really appreciate your time and efforts!
In fact, my question is very similar to this post, except that in my case the number of attributes is pretty big (~300) and not consistent across each ID, so hard coding each attribute might not be a practical solution.
For me, the challenging/difficult parts are:
There are approximately 270 millions lines of input, the total size of the input table is about 60 GB.
Some single values (string) contain comma (,) within, and the whole string will be enclosed with double-quote (") to make the reader aware of that. For example "JPMORGAN CHASE BANK, NA, TX" in ID=53.
The set of attributes is not the same across ID's. For example, the number of overall attributes is 8, but ID=53, 17 and 23 has only 7, 6 and 5 respectively. ID=17 does not have attributes string_country and string_address, so output blank/nothing after the comma.
The input attribute-value table looks like this. In this sample input and output, we have 3 ID's, whose number of attributes can be different depending on we can obtain such attributes from the server or not.
ATTRIBUTE_NAME,ATTRIBUTE_VALUE,ID
num_integer,100,53
string_country,US (United States),53
string_address,FORT WORTH,53
num_double2,546.0,53
string_acc,My BankAcc,53
string_award,SILVER,53
string_bankname,"JPMORGAN CHASE BANK, NA, TX",53
num_integer,61,17
num_double,34.32,17
num_double2,200.541,17
string_acc,Your BankAcc,17
string_award,GOLD,17
string_bankname,CHASE BANK,17
num_integer,36,23
num_double,78.0,23
string_country,CA (Canada),23
string_address,VAN COUVER,23
string_acc,Her BankAcc,23
The output table should look like this. (The order of attributes in the columns is not fixed. It can be sorted alphabetically or by order-of-appearance.)
ID,num_integer,num_double,string_country,string_address,num_double2,string_acc,string_award,string_bankname
53,100,,US (United States),FORT WORTH,546.0,My BankAcc,SILVER,"JPMORGAN CHASE BANK, NA, TX"
17,61,34.32,,,200.541,Your BankAcc,GOLD,CHASE BANK
23,36,78.0,CA (Canada),VAN COUVER,,Her BankAcc,,
This program will do as you ask. It expects the name of the input file as a parameter on the command line.
Update Looking more carefully at the data I see that not all of the data fields are available for every ID. That makes things more complex if the fields are to be kept in the same order as they appear in the file.
This program works by scanning the file and accumulating all the data for output into hash %data. At the same time it builds a hash %headers, that keeps the position each header appears in the data for each ID value.
Once the file has been scanned, the collected headers are sorted by finding the first ID for each pair that includes information for both headers. The sort order for that pair within the complete set must be the same as the order they appeared in the data for that ID, so it's just a matter of comparing the two position values using <=>.
Once a sorted set of headers has been created, the %data hash is dumped, accessing the complete list of values for each ID using a hash slice.
Update 2 Now that I realise the sheer size of your data I can see that my second attempt was also flawed, as it tried to read all of the information into memory before outputting it. That isn't going to work unless you have a monster machine with about 1TB of memory!
You may get some mileage from this version. It scans twice through the file, the first time to read the data so that the full set of header names can be created and ordered, then again to read the data for each ID and output it.
Let me know if it's not working for you, as there's still things I can do to make it more memory-efficient.
use strict;
use warnings;
use 5.010;
use Text::CSV;
use Fcntl 'SEEK_SET';
my $csv = Text::CSV->new;
open my $fh, '<', $ARGV[0] or die qq{Unable to open "$ARGV[0]" for input: $!};
my %headers = ();
my $last_id;
my $header_num;
my $num_ids;
while (my $row = $csv->getline($fh)) {
next if $. == 1;
my ($key, $val, $id) = #$row;
unless (defined $last_id and $id eq $last_id) {
++$num_ids;
$header_num = 0;
$last_id = $id;
print STDERR "Processing ID $id\n";
}
$headers{$key}[$num_ids-1] = ++$header_num;
}
sub by_position {
for my $id (0 .. $num_ids-1) {
my ($posa, $posb) = map $headers{$_}[$id], our $a, our $b;
return $posa <=> $posb if $posa and $posb;
}
0;
}
my #headers = sort by_position keys %headers;
%headers = ();
print STDERR "List of headers complete\n";
seek $fh, 0, SEEK_SET;
$. = 0;
$csv->combine('ID', #headers);
print $csv->string, "\n";
my %data = ();
$last_id = undef;
while () {
my $row = $csv->getline($fh);
next if $. == 1;
if (not defined $row or defined $last_id and $last_id ne $row->[2]) {
$csv->combine($last_id, #data{#headers});
print $csv->string, "\n";
%data = ();
}
last unless defined $row;
my ($key, $val, $id) = #$row;
$data{$key} = $val;
$last_id = $id;
}
output
ID,num_integer,num_double,string_country,string_address,num_double2,string_acc,string_award,string_bankname
53,100,,"US (United States)","FORT WORTH",546.0,"My BankAcc",SILVER,"JPMORGAN CHASE BANK, NA, TX"
17,61,34.32,,,200.541,"Your BankAcc",GOLD,"CHASE BANK"
23,36,78.0,"CA (Canada)","VAN COUVER",,"Her BankAcc",,
Use Text::CSV from CPAN:
#!/usr/bin/env perl
use strict;
use warnings;
# --------------------------------------
use charnames qw( :full :short );
use English qw( -no_match_vars ); # Avoids regex performance penalty
use Text::CSV;
my $col_csv = Text::CSV->new();
my $id_attr_csv = Text::CSV->new({ eol=>"\n", });
$col_csv->column_names( $col_csv->getline( *DATA ));
while( my $row = $col_csv->getline_hr( *DATA )){
# do all the keys but skip if ID
for my $attribute ( keys %$row ){
next if $attribute eq 'ID';
$id_attr_csv->print( *STDOUT, [ $attribute, $row->{$attribute}, $row->{ID}, ]);
}
}
__DATA__
ID,num_integer,num_double,string_country,string_address,num_double2,string_acc,string_award,string_bankname
53,100,,US (United States),FORT WORTH,546.0,My BankAcc,SILVER,"JPMORGAN CHASE BANK, NA, TX"
17,61,34.32,,,200.541,Your BankAcc,GOLD,CHASE BANK
23,36,78.0,CA (Canada),VAN COUVER,,Her BankAcc,,

Dynamic variable different for every Wordpress post: how to declare in loop?

I need a wordpress loop that for every post checks a meta numeric variable previously assigned to each of the taxonomies of the post and returns the sum of these meta variables.
To do so, I think I need a dynamic variable name for the total. I mean something like:
variablerelatedtopost = metataxonomy1 + metataxonomy2 + ... + metataxonomyn
echo variablerelatedtopost
How can I do that? Is it possible to generate a dynamic numeric variable via loop? and HOW can I refer to it in a general way, without adressing it with its name?
Thanks everyone! And sorry for possible English mistakes :P
EDIT: I just realized the code by Alex is not what I wanted. I need a variable which changes name at every post and which value is always = 0. Is there a solution?
can you not just add a counter to your loop like this?
//Total should start # 0 before the loop
$total = 0;
// The Query
$the_query = new WP_Query($args);
// The Loop
while ( $the_query->have_posts() ) : $the_query->the_post();
$amount = get_post_meta($post->ID, 'the_meta_data_field', true);
$total = $total + $amount;
endwhile;
//echo total
echo $total;
I found the solution to my problem: an array which increases its lenght at every cicle of the loop. I know it's simple but since I'm just a beginner it took me a while to think about it. I post the code here so maybe it can help someone (and if you find bugs or have improvements, please tell me)
//Before the loop, empty array
$totale = array();
// WP Loop
while ( $loop->have_posts() ) : $loop->the_post();
$totale[] = 0;
$indice = (count($totale)) - 1;
// $termvariable was previously set up as a term meta value
if( has_term( 'numberofterm', 'nameoftaxonomy' ) ) {
$totale[$indice] = $termvariable + $totale[$indice];
}

How to use a dynamic smarty variable in foreach loop

Can anyone tell me how to use dynamic variables in smarty foreach loop. I am trying to create a module in prestashop and m very close to get it done.
here's my code:
//file name index.php
foreach( $subCategories as $s )
{
$foo = intval($s['id_category']);
$k = new Category($foo);
$var1 = "subSubCategories.$foo";
$var1 = $k->getSubCategories(1);
$smarty->assign(array('foo'.$foo => $var1));
}
//file name:index.tpl
{assign var=foo value=$foo$cat}
//where $cat is a variable that counts the number of categories
{if isset($foo) AND $foo}
{foreach from=$foo item=subCategories name=homesubCategories}
<p>{$subCategories.name}</p>
{/foreach}
{else}
<p>{l s='test failed'}</p>
{/if}
I've exhausted all of my resources and knowledge and feeling quite helpless at this moment. so plz help me out.
I am trying to create dynamic variables ('foo'.$foo i.e. foo1, foo2, and so on) depending on the number of sub-categories. I think m successful up to this point. Now moving on to the tpl file, here I want to access the dynamically created variable (foo2, foo3 etc.) using foreach. Now if I am doing this: {assign var=foo value=$foo3} I succeed in fetching the values from this subcategory using the same foreach loop. But when I do this: {assign var=foo value=$foo$catx} (where $catx stores the values for category id) it fails. Please help.
I use such code in section loop (for Smarty 2):
{section name=buildings loop=7 start=1 step=1 max=7}
<tr>
{assign var=part_number value="part`$smarty.section.buildings.index`_number"}
<td class="number">
<input class="number xshort" name="part{$smarty.section.buildings.index}_number" value="{$data.$part_number}" type="text">
</td>
</tr>
{/section}
As you can see, there are a creation of dynamic variable part_number (see backticks in value block). And then, you can use it as value="{$data.$part_number}".
Your $smarty->assign() call is incorrect; you've only got one parameter being sent to it, but it needs two parameters (the variable name, followed by the value). Based on your template code (looping through variable $foo), your loop should be something like this in PHP:
//file name index.php
$subcats = array();
foreach($subCategories as $s) {
$foo = intval($s['id_category']);
$k = new Category($foo);
$subcats[$foo] => $k->getSubCategories(1);
}
$smarty->assign('foo', $subcats);
Then it also looks like you're not using the Smarty {foreach} quite properly either. You're declaring the name attribute, of the foreach loop, but then not using it properly. Assuming $k->getSubCategories(1) returns a string, the smarty code would just have to be:
{foreach from=$foo item=subCategories}<p>{$subCategories}</p>{/foreach}
If $k->getSubCategories(1) returns an array with a 'homesubCategories' element (which is what I think you're trying to get at with your Smarty code), you still don't need the 'name' value on the foreach. You'd then just do:
{foreach from=$foo item=subCategories}<p>{$subCategories.homesubCategories}</p>{/foreach}
With $foo = intval($s['id_category']); you defined $foo as an integer.
Then you concat the string with $smarty->assign(array('foo'.**$foo** => $var1));
Correct is:
$foo = $s['id_category'];
$smarty->assign(array('foo'.$foo => $var1));
Dynamically named variables are generally a very bad design choice, making everything much more difficult than it needs to be.
If you have a set of elements you need to loop over or index into, put them in an array; then you don't need to do any magic assignments, as you can use normal foreach loops or array key access:
//file name index.php
// Build the array first, then assign it to Smarty at the end
$foo_array = array();
foreach($subCategories as $s)
{
$foo = intval($s['id_category']);
$k = new Category($foo);
// This line is redundant as you over-write on the following line:
// $var1 = "subSubCategories.$foo";
$var1 = $k->getSubCategories(1);
$foo_array[ $foo ] = $var1;
}
// Assigning one variable, so just pass name and value to $smarty->assign()
$smarty->assign('foo_array', $foo_array);
//file name:index.tpl
{* Look for the entry in the outer array with key "$cat", then loop over it *}
{foreach from=$foo_array[$cat] item=subCategories}
<p>{$subCategories.name}</p>
{/foreach}
it's possible to call variable dynamically created in template with this statement:
if for example $index = 2
{$foo{$index}}
then this will call variable with name {$foo2}

Powershell and SQL parameters. If empty string, pass DBNull

I got this parameter:
$objDbCmd.Parameters.Add("#telephone", [System.Data.SqlDbType]::VarChar, 18) | Out-Null;
$objDbCmd.Parameters["#telephone"].Value = $objUser.Telephone;
Where the string $objUser.Telephone can be empty. If it's empty, how can I convert it to [DBNull]::Value?
I tried:
if ([string]:IsNullOrEmpty($objUser.Telephone)) { $objUser.Telephone = [DBNull]::Value };
But that gives me the error:
Exception calling "ExecuteNonQuery" with "0" argument(s): "Failed to convert parameter value from a ResultPropertyValueCollection to a String."
And if I convert it to a string, it inserts an empty string "", and not DBNull.
How can this be accomplished?
Thanks.
In PowerShell, you can treat null/empty strings as a boolean.
$x = $null
if ($x) { 'this wont print' }
$x = ""
if ($x) { 'this wont print' }
$x = "blah"
if ($x) { 'this will' }
So.... having said that you can do:
$Parameter.Value = $(if ($x) { $x } else { [DBNull]::Value })
But I'd much rather wrap this up in a function like:
function CatchNull([String]$x) {
if ($x) { $x } else { [DBNull]::Value }
}
I don't know about powershell, but in C# I would do something like this:
if ([string]::IsNullOrEmpty($objUser.Telephone))
{
$objDbCmd.Parameters["#telephone"].Value = [DBNull]::Value;
}
else
{
$objDbCmd.Parameters["#telephone"].Value = $objUser.Telephone;
}
Always append +"" at the end of db values...
$command.Parameters["#EmployeeType"].Value= $ADResult.EmployeeType + ""
Many years later, let me clarify:
Josh's answer shows a helpful simplification for testing strings for emptiness (relying on PowerShell's implicit to-Boolean conversion[1]), but it is unrelated to Tommy's (the OP's) problem.
Instead, the error message
"Failed to convert parameter value from a ResultPropertyValueCollection to a String."
implies that it is the non-null case that caused the problem, because $objDbCmd.Parameters["#telephone"].Value expects either a string value or [DBNull]::Value, whereas $objUser.Telephone is of type [ResultPropertyValueCollection], i.e. a collection of values.
Thus, in the non-null case, a string value must be assigned, which must be derived from the collection; one option is to take the first collection element's value, another would be to join all values with a separator to form a single string, using, e.g., [string]::Join(';', $objUser.Telephone) or, if joining the elements with spaces is acceptable (not a good idea with multiple phone numbers), simply with "$($objUser.Telephone)".[2]
Detecting an empty collection via [string]:IsNullOrEmpty() actually worked, despite the type mismatch, due to how PowerShell implicitly stringifies collections when passing a value to a [string] typed method parameter.[2]
Similarly, using implicit to-Boolean conversion works as expected with collections too: an empty collection evaluates to $false, a non-empty one to $true (as long as there are either at least two elements or the only element by itself would be considered $true[1])
Therefore, one solution is to use the first telephone number entry:
$objDbCmd.Parameters["#telephone"].Value = if ($objUser.Telephone) {
$objUser.Telephone[0].ToString() # use first entry
} else {
[DBNull]::Value
}
Note: If $objUser.Telephone[0] directly returns a [string], you can omit the .ToString() call.
In PowerShell v7+ you can alternatively shorten the statement via a ternary conditional:
$objDbCmd.Parameters["#telephone"].Value =
$objUser.Telephone ? $objUser.Telephone[0].ToString() : [DBNull]::Value
[1] For a comprehensive summary of PowerShell's automatic to-Boolean conversions, see the bottom section of this answer.
[2] When implicitly converting a collection to a string, PowerShell joins the stringified elements of a collection with a single space as the separator by default; you can override the separator with the automatic $OFS variable, but that is rarely done in practice; e.g., array 'foo', 'bar' is converted to 'foo bar'; note that this conversion does not apply when you call the collection's .ToString() method explicitly, but it does apply inside expandable (interpolating) strings, e.g., "$array".