Yii Framework Forum: multi dimensional arrays in session - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

multi dimensional arrays in session Indirect modification of overloaded element of CHttpSession has no eff Rate Topic: ***** 2 Votes

#1 User is offline   MarcS 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 97
  • Joined: 05-July 09

Posted 08 September 2009 - 10:38 AM

Hi everyone,
I've got a problem with sessions and I'm not sure if this just won't work or I'm doing something wrong

I have the following code
		$session = Yii::app()->session['foo']['bar'] = 3;


which gives the error
Indirect modification of overloaded element of CHttpSession has no eff

when I try
		$session = Yii::app()->session;
		$session['foo']['bar'] = 3;

I get the same error

is there any way to make this work?
0

#2 User is offline   Mukke 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 51
  • Joined: 05-September 09
  • Location:Brussels (Belgium)

Posted 08 September 2009 - 11:11 AM

from the docs:

session property read-only
public CHttpSession getSession()
the session component

i think the correct aproach is

$session=new CHttpSession;
  $session->open();
  $session['foo']['bar']=$value;

(\ /)
( . .)
C('')('') -- This is Tiny Bunny. Copy Tiny Bunny into your signature to help him on his way to world domination.
Posted Image
0

#3 User is offline   MarcS 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 97
  • Joined: 05-July 09

Posted 08 September 2009 - 12:31 PM

if I'm not mistaken this approach is exactly the same as
                $session = Yii::app()->session;
                $session['foo']['bar'] = 3;


View PostMukke, on 08 September 2009 - 11:11 AM, said:

from the docs:

session property read-only
public CHttpSession getSession()
the session component

i think the correct aproach is

$session=new CHttpSession;
  $session->open();
  $session['foo']['bar']=$value;


0

#4 User is offline   sluderitz 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 105
  • Joined: 26-February 09
  • Location:Germany

Posted 08 September 2009 - 03:50 PM

I had the same issue.
CHttpSession implements the ArrayAccess interface,
so when you do $session['foo'] = $value this function is actually called:
public function offsetSet($offset,$item) {
    $_SESSION[$offset]=$item;
}


When you do $value = $session['foo'] then this funciton is called:
public function offsetGet($offset) {
    return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
}


So I think when you do $session['foo']['bar'] = $value then first offsetGet is called and $_SESSION['foo'] is returned as a copy (not a reference) and then ['bar'] is set on that copied array.
This is how I understood the bug reports on php.net. There where suggestions to have offsetGet return a reference. Older versions of PHP did not seem to behave like this and I am not sure how the newest PHP version behaves.

Currently my solution is this:
$session = Yii::app()->session;
$temp = $session['foo'];
$temp['bar'] = 3;
$session['foo'] = $temp;


This is not nice and I hope somebody can tell me a better solution.

Of course you could always access the $_SESSION variable directly
0

#5 User is offline   MarcS 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 97
  • Joined: 05-July 09

Posted 09 September 2009 - 06:22 AM

@sluderitz

what you suggested is what I did for now. Of course this is not very satisfiying but I guess there is no other way atm
0

#6 User is offline   pestaa 

  • past Yii dev member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 705
  • Joined: 07-May 09
  • Location:Hungary

Posted 09 September 2009 - 12:36 PM

This workaround seems very inevitable, but
Yii::app()->session['foo'] = array('bar' => 3);

might look prettier for you.
0

#7 User is offline   MarcS 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 97
  • Joined: 05-July 09

Posted 09 September 2009 - 03:16 PM

View Postpestaa, on 09 September 2009 - 12:36 PM, said:

This workaround seems very inevitable, but
Yii::app()->session['foo'] = array('bar' => 3);

might look prettier for you.


It does but it doesn't really solve anything
the problem does not appear when initially setting the foo property. but when you wanna change one something
suppose something like this

Yii::app()->session['foo'] = array('bar1' => 3, 'bar2'=>4);

now I wanna change bar2
$data = Yii::app()->session['foo'];
$data['bar2'] = 'new value';
Yii::app()->session['foo'] = $data;

this is a bit inconvenient.

I'm wondering if it would make sense to extend the session component with a method that takes care of this
for example
Yii::app()->session->set('foo.bar2','value');


what do you think pestaa?
1

#8 User is offline   qiang 

  • Yii Project Lead
  • Yii
  • Group: Yii Dev Team
  • Posts: 5,902
  • Joined: 04-October 08
  • Location:DC, USA

Posted 09 September 2009 - 04:34 PM

Unfortunately, this is a limit by PHP. We can't think of a good way to solve it. Your proposal of using 'foo.bar2' is not very sounding because it is very likely someone may use 'foo.bar2' as a 1D key rather than 2D.
0

#9 User is offline   TRON-00 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 15-October 09

Posted 15 October 2009 - 07:15 PM

For some reason, using $_SESSION instead of $session seems to work:

$session = Yii::app()->session;

// Set session var
$_SESSION['foo']['bar'] = 'result';

// Change session var
$_SESSION['foo']['bar'] = 'result 2';


I am using CDbHttpSession and it holds the session in the database.
1

#10 User is offline   FDisk 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 05-January 10

Posted 27 December 2010 - 02:43 PM

		Yii::app()->session->add('test',array('bar1' => 3, 'bar2'=>4));
		print_r(Yii::app()->session->get('test'));


Results are:
Array
(
    [bar1] => 3
    [bar2] => 4
)

2

#11 User is offline   ianaré 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 50
  • Joined: 05-November 10
  • Location:Terra (III in Sol system)

Posted 04 February 2011 - 05:49 AM

View PostFDisk, on 27 December 2010 - 02:43 PM, said:

		Yii::app()->session->add('test',array('bar1' => 3, 'bar2'=>4));
		print_r(Yii::app()->session->get('test'));


Results are:
Array
(
    [bar1] => 3
    [bar2] => 4
)



This doesn't address the problem though. We want to be able to access and set variable in one line of code, and
Yii::app()->session->add('test')['bar1']
will not work, neither will
Yii::app()->session->get('test')['bar1']
.
0

#12 User is offline   ianaré 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 50
  • Joined: 05-November 10
  • Location:Terra (III in Sol system)

Posted 04 February 2011 - 06:11 AM

Having several Yii apps sharing the same session, I REALLY needed a way of dividing the variables as several developers are working on the project and it would be simply impossible to make sure one wasn't overwriting data of another.

I decided to use objects instead of arrays though as this will allow greater flexibility in the future. Additionally, it would be possible to use an object implementing ArrayAccess if array style access becomes important.

Now, for the code. Here is my modified session class :

class MySession extends CHttpSession
{	
	public function setInstance($sessionName, $className='stdClass')
	{
		if (!isset($_SESSION[$sessionName])) {
			$_SESSION[$sessionName] = new $className();
		}
	}
}


When I need to add a division, I declare it like so :
class MyWebUser extends CWebUser
{
	public function afterLogin($fromCookie)
	{
		Yii::app()->session->setInstance('secretData');
		Yii::app()->session['secretData']->secret = 'superSecretThing';

		[....]
	}
}

... though of course this could be anywhere. The important thing is that it only needs to be done once.

Once the object has been initialized by the 'setInstance' method, it can be accessed and modified from any other parts of the code without having to set its instance again.
class UserController extends CController
{
	public function actionTest1()
	{
		Yii::app()->session['secretData']->secret = 'ohNoesYouFoundMySecret';
	}

	public function actionTest2()
	{
		var_dump(Yii::app()->session['secretData']->secret);
	}
}

0

#13 User is offline   ohrsman 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 24-May 12

Posted 10 June 2012 - 08:25 AM

hi,
ill do something like that

//init session var
if(!isset(Yii::app()->session['myvar'])){
  Yii::app()->session['myvar'] = serialize(array());
}
//add new item to session myvar
$myvarArray = unserialize(Yii::app()->session['myvar']);
$myvarArray[] = 'new value';
Yii::app()->session['myvar'] = serialize($myvarArray);

//get session myvar as array
$myvarArray = unserialize(Yii::app()->session['myvar']);

0

#14 User is offline   choppingblock 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 17
  • Joined: 10-March 11
  • Location:Essen, Germany

Posted 10 July 2012 - 12:16 PM

I had to fiddle a lot with this issue... my problem was that i had to handle multidimensional arrays in various depths.
The solution was quite simple at last... i put all session data in a variable as an array, did all the manipulations on that array and then just wrote back the changed part of the array to the session via "add()".

$session = Yii::app()->session->toArray();

// the data to put into the session
foreach($data as $key => $value) {
	$session['dimension1']['dimension2']['dimension3'][$key] = $value;
}

// some more data on a different level
$session['dimension1']['dimension2']['foo'] = 'bar';

Yii::app()->session->add('dimension1', $session['dimension1']);


Not really elegant, but works quite well for me.
0

#15 User is offline   glyph 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 16
  • Joined: 20-April 12
  • Location:Michigan, USA

Posted 03 August 2012 - 02:34 PM

I had some similar issues that led me here.
Not only can you not use multidimensional arrays, but since everything is converted to string, you can't use boolean or integer either.


I ended up having to check the session var I thought was a bool as a string instead. This tripped me up for a while.

<?php echo (Yii::app()->session['myVar']=='true')?'Foo':'Bar'; ?>


(note the quotes around 'true')

serialize sounds like a good workaround to the array issue.
-------------------------------------------------
Glyph Imaging and Data Services
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users