Posted by vascot on December 20, 2009 at 6:11pm
15 followers
| Project: | Drush |
| Component: | Core Commands |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | closed (fixed) |
Issue Summary
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 ??????
Comments
#1
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.
#2
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_settingsDon'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] settingThis would handle setting members of arrays, and
$ drush variable-set varname->propertyname settingsWould 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.
#3
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 arrayo: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.
#4
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.
#5
Don't like it; too much shell work, too fragile. It's a start in the right direction, though.
#6
So what do you think of my proposal at the bottom of my comment #2?
#7
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.#8
I just re-read moshe's comment in #1. Shall we just set this to "won't fix"?
#9
OK now that we have the workaround, can someone please provide an example of how to use
drush scriptto set an array?#10
<?php
$data = array(
'foo' => 'bar',
'baz' => 'gilligan',
);
variable_set('var_name', $data);
?>
#11
Interested in this as well.
#12
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.
#13
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...
#14
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.
#15
I just committed #14. It may not be that helpful here, but it is generally a good thing.
#16
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);"
#17
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.#18
#19
#12 sounds good to me.
#20
Committed json support as input and output format.
#21
+1
#22
Won't apply cleanly. Needs reroll.
#23
sub, this would help me out
#24
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 valuedrush vset --format=json foo -
But a simple example of setting an array would be so much better.
#25
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 -#26
Committed the new example to master in 5e6f49b
#27
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 updateupdate_notify_emails: "-"
# # #
So, when is drush 5.x going to be production worth?
Best,
Sam
#28
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.
#29
Automatically closed -- issue fixed for 2 weeks with no activity.