Welcome Guest, Not a member yet? Register   Sign In
Annoying codependant library problem
#1

[eluser]kirilisa[/eluser]
Hi folks,

I just have a quick question on the viability of codependent libraries. Let's say I have two libraries that I am autoloading: session and auth. No matter what I do, I will never be able to access them each from each other, no?

e.g. if I wrote

Code:
//session.php
$this->ci =&get;_instance();
$this->ci->load->library('auth');

AND

//auth.php
$this->ci =&get;_instance();
$this->ci->load->library('session');

it clearly doesn't make sense as that basically represents an infinite loop of the libraries' loading each other. The CI result is that it doesn't break, but the second library (auth) never gets session loaded. i.e. I can set up one of them to access the other one, but not set it up so that they can access each other.

I'm sure you wonder why I'm asking this so I will tell you. My auth class necessarily uses the session a few times (for access checking, to get a stored userId to look up page access from the DB, etc., and to point to sess_destroy from its logout method) - I don't really see any way around this. The reason I was thinking of making session access auth was for use of a particular method - $auth->log_logout(), where I was trying to log a user's logout date/time even if his logout was indirect in that it resulted from a session expiration. I can of course just write a second log_logout method within session.php but it will be redundant.

However, given that I am trying to log peoples' logouts whether via clicking 'logout' or due to session expiration, I can't think of any really clean way to do it.

Anyway else ever tried to implement something of this sort?

Thanks!
#2

[eluser]mikegioia[/eluser]
I'm not sure I understand what you're trying to do. I handle logouts by having the user go to domain.com/logout. The logout controller uses the session library to destroy the session. From the controller I'd be able to then call any function to log the user's logout, like auth->log_logout. You really don't need to have the session class access your auth class. The session class should just take care of sessions and your controller function can call any subsequent logging methods.

Let me know if I had that wrong though,
Mike
#3

[eluser]kirilisa[/eluser]
That is what I meant when I said it is easy to implement when your user actually logs off like he is supposed to. But what if he doesn't? What if he just walks away for say 4 hours? When he returns, his session would have expired (that is, if you have set it that way - I have my sessions expire 2 hours after last activity) - so if he reloads the page or tries to browse somewhere, it boots him back to the logon page.

Now that action is handled entirely by the session class, which when instantiated runs a check to see if the session has expired and if so destroys it. It is not run through a controller because the session checking/instantiation is done automatically before any controller is accessed. Thus the session itself needs to trigger the logging to DB step, right before it destroys the session and boots back to the logon page. Does that make sense?
#4

[eluser]wiredesignz[/eluser]
If the libraries are autoloaded then they have access to each other via the CI super object.

Code:
//session.php
$ci =& get_instance();
$ci->auth->do_stuff();

//auth.php
$ci =& get_instance();
$ci->session->do_stuff();
#5

[eluser]kirilisa[/eluser]
That is what I thought initially, but I saw that that is not actually the case in this instance.

From my tests, it appears that when you autoload a session class it is autoloaded and the session is instantiated before all the rest of the libraries you specified in autoload.php have been loaded. For instance, if I did:

Code:
// autoload.php
$autoload['libraries'] = array('session', 'auth');
...

//session.php
function __construct() {
  echo "instantiating session!<br>";
  $this->object =& get_instance();
  foreach ($this->object as $key => $val) echo "$key<br>";
}
...

//auth.php
function __construct() {
  echo "instantiating auth!<br>";
  $this->object =& get_instance();
  foreach ($this->object as $key => $val) echo "$key<br>";
}
...

and then go to the very first page of my CI app, I get the following:

instantiating session!
_ci_scaffolding
_ci_scaff_table
config
input
benchmark
uri
output
lang
load
db

instantiating auth!
_ci_scaffolding
_ci_scaff_table
config
input
benchmark
uri
output
lang
load
db
encrypt
session

You can see that session has not in fact loaded auth yet but auth has loaded session. If I switched their order in autoload it would be the other way round.

If I do code such as your example, I get a big error box:
Message: Undefined property: Logon::$auth


I guess one way around this is to not call get_instance() within my class constructor. That's a bit annoying though because that means I'll end up calling it all over the place. I guess the moral of this story is that you can't set a CI instance on instantiation of any class/library which you plan to autoload?
#6

[eluser]kirilisa[/eluser]
Actually never mind my last paragraph. For purposes of my above problem, it doesn't matter if I call $ci =& get_instance(); in the constructor or not, it still won't work.

Since the session expiry is checked as soon as session is instantiated, and thus before CI has loaded auth, no matter where I call $ci =& get_instance(); auth won't have been loaded yet. I suppose I could just switch the order in the autoload and just make sure the auth lib doesn't have any methods that access the session and are automatically called... I don't like having to depend on things being in a certain order, but ah well.

You can't solve it by using $ci->load->library('whatever') in the constructor either, because then that bumps you prematurely into the second library before the first library finished loading, and you still have exactly the same problem...
#7

[eluser]webthink[/eluser]
I know what you're talking about... the problem here is that session is not only loaded (when autoloaded) but it's also "run" IE all the checking to see if it's a valid session happens upon construction.

I think though that it's bad form to put your logout business logic within the session handler itself and this is where you're falling down. What you could do is to change the session handler to set an attribute ($this->expired = TRUE) then have a hook (or some other form of auto run code) that checks that attribute and if ($this->session->expired == TRUE) $this->auth->logout;
#8

[eluser]wiredesignz[/eluser]
I encountered a similar problem with Modular Extensions. My solution was to set an array in the super object ($CI) to contain values I needed to pass between libraries. Each library would check and set/unset the array values as needed.

Your session library could set a value dependent on the session state and the auth library would react to the values appropriately.
#9

[eluser]kirilisa[/eluser]
Ah yeah, I should have thought of that! I was so hating the thought of putting DB update in my session library. It's just... wrong. Now I've followed wiredesignz's remark and it's all good. Thanks guys!
#10

[eluser]webthink[/eluser]
I'm not getting this... why would you set a variable in the super object when you can just set one in the session object itself? This is what OOP/encapsulation is all about.




Theme © iAndrew 2016 - Forum software by © MyBB