Hi,
is it possible to set the value of a variable that is an array using vset? Or is there an elegant solution to solve this problem?

$ drush vget foo
foo: Array
(
[bar] => 1
)

$ drush vset foo ??????

CommentFileSizeAuthor
#4 drush_variable-set_serialized_values.patch534 bytesapotek
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

moshe weitzman’s picture

Not currently possible. For now, I think you want to use eval(variable_set()) or script command.

We could conceivably support incoming array via our JSON REST API. Not sure that would be useful in practice. Feedback welcome.

apotek’s picture

Title: use vset and arrays » use variable-set with arrays and objects
Version: 6.x-1.x-dev »

I originally posted this at #3141794, but then saw this feature request, and decided it was more appropriate here.

+1 for support for setting a variable within a serialized value. If the variable setting is a serialized array, and you want to change one member of the array, it's pretty tough to parse and set accurately via shell. I see you can pipe it out with --pipe and let cli php handle it. Is that the recommended approach, something like?

$ php -r '$s=` drush variable-get theme_zen_settings --pipe` ; eval($s) ; $variables["theme_zen_settings"]["zen_rebuild_registry"]=1; $var_to_set = serialize($variables["theme_zen_settings"]);echo "$var_to_set";' | sed -e "s/^/'/g" -e "s/$/'/g" | xargs drush --yes variable-set theme_zen_settings

Don't try this. it doesn't work quite, as drush interprets the value as a plain string, not an string representing a serialized array in variable-set. My point is simply that this is obviously *extremely* brittle, even if I *could* get this to work through some shell/php trickery.

My proposal would be to extend variable-set with

$ drush variable-set varname[arraymember] setting

This would handle setting members of arrays, and

$ drush variable-set varname->propertyname settings

Would handle setting properties of any objects stored in the variables table (don't know of any). The idea would be to parse the first param (varname or varname[arraymember] or varname->propertyname) to see whether to handle it as a literal, array or object.

apotek’s picture

Another way to handle this would be to use the terribly brittle approach, piping to shell, etc, but then simply parse the incoming string not just for string versus int, but whether it starts with

a:nn:{  //this is an array
o:nn:{ //this must be an object

Not nearly as robust as the proposal above, but would be a quicker fix.

Or, better than parsing the first characters would be checking if incoming value is unserializable...

...
$result = @unserialize($args[1]);
if ($result) { //we have passed a serialized value instead of just an int or string
  //set the variable to its unserialized value
  drush_op('variable_set', $args[0], $result);
} else {
  //set the variable normally
  drush_op('variable_set', $args[0], $args[1];
}

Happy to contribute this as a patch if anyone thinks it's worth it.

apotek’s picture

Here's a 5 line patch to variable.drush.inc that allows for setting values as serialized arrays or objects.

Unfortunately it still relies on horrendous amounts of shell work, but it is a workaround.

$ php -r '$s=` drush variable-get theme_cti_flex_settings --pipe` ; eval($s) ; $variables["theme_cti_flex_settings"]["_rebuild_registry"]=1; $var_to_set = serialize($variables["theme_cti_flex_settings"]);echo "$var_to_set";' | sed -e "s/^/'/g" -e "s/$/'/g" | xargs drush --yes variable-set theme_cti_flex_settings

theme_cti_flex_settings was set to Array.

Of course, this is only gonna work as long as there are no single-quotes in the contents of the serialized array or object.

greg.1.anderson’s picture

Don't like it; too much shell work, too fragile. It's a start in the right direction, though.

apotek’s picture

So what do you think of my proposal at the bottom of my comment #2?

greg.1.anderson’s picture

What if the user was trying to set an array with seven members? What if the user only specified three of the members; are the other array values set to zero, or preserved without change? What if you write a script that assumes the array has seven members, and then a new version of Drupal or the Drupal module comes out, and an eighth member is added?

It seems to me that a syntax more in line with JSON encoding is what's needed here; the problem is that structures like that are really hard to enter from the command line.

When dealing with arrays, it might be better to just use drush script. Then you can express exactly what you mean in code.

greg.1.anderson’s picture

I just re-read moshe's comment in #1. Shall we just set this to "won't fix"?

gbell12’s picture

OK now that we have the workaround, can someone please provide an example of how to use drush script to set an array?

moshe weitzman’s picture

Status: Active » Closed (won't fix)
$data = array(
  'foo' => 'bar',
  'baz' => 'gilligan',
);
variable_set('var_name', $data);
techgirlgeek’s picture

Version: » All-versions-4.2
Component: Code » PM (dl, en, up ...)

Interested in this as well.

msonnabaum’s picture

Version: All-versions-4.2 »
Status: Closed (won't fix) » Needs work

This came up in IRC again today. I think we should have vget accept json via STDIN and give vset the "format" option so it can output json. We already do this on cache-get/set.

Basically, I don't think the difficulty of entering it on the cli is relevant. Let's assume its being outputted from another command.

anarcat’s picture

The way to pass stuff through stdin/stdout/JSON is usually --backend. Unfortunately, drush vget --backend doesn't include the variables anywhere else than as a string in the "output" variable. vget would need to set something somewhere so they would be exported, and do the same with vset. Maybe that's already the case...

greg.1.anderson’s picture

If vget just returns the variables in an array (as the function result), then it will be put into the 'object' item of the backend invoke results.

moshe weitzman’s picture

I just committed #14. It may not be that helpful here, but it is generally a good thing.

suffusionofyellow’s picture

if running from the shell directly, remember to protect variable names i.e.:
drush ev "\$a=variable_get('gmap_default');\$a[markermode]='1';variable_set('gmap_default',\$a);"

greg.1.anderson’s picture

I prefer to write #16 as:

drush ev '$a=variable_get("gmap_default");$a[markermode]="1";variable_set("gmap_default",$a);'

It's easier to not have to think about backslashing every $, but I have to admit, I sometimes mess up and type ' instead of " when I'm doing this.

moshe weitzman’s picture

Title: use variable-set with arrays and objects » use variable-set with arrays and objects. Accept JSON via STDIN like cache-set
moshe weitzman’s picture

Component: PM (dl, en, up ...) » Core Commands

#12 sounds good to me.

moshe weitzman’s picture

Status: Needs work » Patch (to be ported)

Committed json support as input and output format.

kenorb’s picture

+1

moshe weitzman’s picture

Won't apply cleanly. Needs reroll.

boombatower’s picture

sub, this would help me out

rfay’s picture

Could we please have an issue summary explaining how this actually works? Very difficult to parse the comments here. Just an example will do. drush help vset offers

 php -r "print json_encode(TRUE);" |       Set foo to a boolean value          
 drush vset --format=json foo -                                                

But a simple example of setting an array would be so much better.

rfay’s picture

Here's an example with a simple array:

php -r "print json_encode(array('drupal', 'simpletest', 'leftandright', 'category'));"  | drush vset --format=json project_dependency_excluded_dependencies -
moshe weitzman’s picture

Committed the new example to master in 5e6f49b

Michael-IDA’s picture

Just FYI for those with a standard drush install (currently drush version 4.5), trying to set an array per example in #25 will destroy the variable for drush.

[~/public_html/testd7]# drush vget update
update_notify_emails: Array
(
    [0] => admin@example.com
)


[~/public_html/testd7]# php -r "print json_encode(array('testd7@inet-design.com'));"  | drush vset --format=json update_notify_emails -
Enter a number to choose which variable to set.
 [0]  :  Cancel
 [1]  :  update_notify_emails

Cancelled

[~/public_html/testd7]# drush vget update
update_notify_emails: Array
(
    [0] => admin@example.com
)


[~/public_html/testd7]# php -r "print json_encode(array('testd7@inet-design.com'));"  | drush vset --format=json update_notify_emails
No value specified.                                                      [error]

[~/public_html/testd7]# php -r "print json_encode(array('testd7@inet-design.com'));"  | drush vset --format=json update_notify_emails -
Enter a number to choose which variable to set.
 [0]  :  Cancel
 [1]  :  update_notify_emails

Cancelled

[~/public_html/testd7]# php -r "print json_encode(array('testd7@inet-design.com'));"  | drush vset --yes --format=json update_notify_emails -
update_notify_emails was set to -.                                       [success]

[~/public_html/testd7]# drush vget update
update_notify_emails: "-"

You can successfully set/change the variable through /admin/config/system/site-information, but drush still shows the corrupted variable:

[~/public_html/testd7]# drush vget update
update_notify_emails: "-"

# # #
So, when is drush 5.x going to be production worth?

Best,
Sam

msonnabaum’s picture

Status: Patch (to be ported) » Fixed

Since this is new functionality I'd rather not backport it into 4.x. Someone can reopen with a patch if they feel strongly about it.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

dhaval_panara’s picture

Any buddy know why we are using hyphen sign (-) in last. Is there any difference if we are not using it?

For example : php -r "print json_encode(array('drupal', 'simpletest', 'leftandright', 'category'));" | drush vset --format=json project_dependency_excluded_dependencies -

helmo’s picture

Version: » All-versions-4.2
Issue summary: View changes

@dhaval_panara The hyphen indicates that the new value should be read from stdin

dhaval_panara’s picture

@helmo Thanks....