Symfony Session Last Request Time - php

Is it possible to make an action (more specifically 'ajax/heartbeat') not update last request time for the session ?
It is used for fetching notifications etc, so it shouldn't update timeout on sessions or they will never expire.
If the user is doing stuff on the page (onmousemove) I set update=true else update=false

Well, you will have to hook into the User lib of Symfony.
lastRequest is updated during the initialization of the User lib (ie: inside sfBasicSecurityUser).
Inside your app/[appname]/lib/myUser.class.php, extends this initialize function to not set the request time. Something ugly like that:
public function initialize(sfEventDispatcher $dispatcher, sfStorage $storage, $options = array())
{
$lastRequest = $this->getLastRequestTime();
parent::initialize($dispatcher, $storage, $options);
if (condition)
{
$this->lastRequest = $lastRequest;
}
}
The only things you need to find is, how to catch the module/action from the myUser lib and then place it in condition.

Related

Laravel redirect and continue executing script

How can I redirect user and then store data in database about that user.
return Redirect::to('http:www.google.com');
// Strore analytics
$ip = $_SERVER['...']
$analytic = new Analytic();
$analytic->ip = $ip;
$analytic->save();
Actually there is not only ip. I need to store a lot more data and if I first store that and then return redirect user needs to wait until everything is finished.
How to first redirect and then continue savin data?
Basically you can't do that. Once you redirect the user to a different location then the code after that line won't be executed. You should save the data first and then redirect and it shouldn't take much time (IMO).
But...
If you want to redirect the user first (without saving the data) then you may use Laravel's queue. You may create a class like this:
class SaveData {
public function fire($job, $data)
{
//
}
}
Then you may use the class like this:
Queue::push('SaveData', array('ip' => $ip, 'otherField' => 'value'));
return Redirect::to('someurl');
There are several drivers available and you need to setup configuration in app/config/queue.php, so read more about queues. This is just a basic idea about queue, read more on the Laravel website.
Are you using Sentry to Handle User sessions??
https://cartalyst.com/manual/sentry
http://bundles.laravel.com/bundle/sentry
eg,
$user = Sentry::getUser();
if ( isset($user) )
{
$id = Helpers::loggedInUser()->id;
$ip = Helpers::loggedInUser()->ip;
}

Does PHP's Laravel 4 hit the Database on every call to the Auth class?

I am building my first Laravel 4 Application (PHP).
I find myself needing to call somthing like this often in most of my Models and Controllers...
$this->user = Auth::user();
So my question is, is calling this several times in the application, hitting the Database several times, or is it smart enough to cache it somewhere for the remainder of the request/page build?
Or do I need to do it differently myself? I glanced over the Auth class but didnt have time to inspect every file (16 files for Auth)
Here is the code for the method Auth::user().
// vendor/laravel/framework/src/Illuminate/Auth/Guard.php
/**
* Get the currently authenticated user.
*
* #return \Illuminate\Auth\UserInterface|null
*/
public function user()
{
if ($this->loggedOut) return;
// If we have already retrieved the user for the current request we can just
// return it back immediately. We do not want to pull the user data every
// request into the method becaue that would tremendously slow the app.
if ( ! is_null($this->user))
{
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
$user = null;
if ( ! is_null($id))
{
$user = $this->provider->retrieveByID($id);
}
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
$recaller = $this->getRecaller();
if (is_null($user) and ! is_null($recaller))
{
$user = $this->provider->retrieveByID($recaller);
}
return $this->user = $user;
}
To me, it looks like it will get the user from the database only once per request. So, you can call it as many times as you want. It will only hit the DB once.
Auth::user() only hits the DB once, so it's not a problem invokes it many times. Btw, you can cache useful information of the user that you want to access frequently.

Sessions in ZF2

Could you tell me how to properly use sessions in ZF2? So far I have this code:
"session" =>
[
"remember_me_seconds" => 2419200,
"use_cookies" => true,
"cookie_httponly" => true
]
That's the session config I copied from some post here on stackoverflow. Now should I put this code into module.config.php in each module that uses sessions or in the Application module?
public function onBootstrap(EventInterface $Event)
{
$Config = $Event->getApplication()->getServiceManager()->get('Configuration');
$SessionConfig = new SessionConfig();
$SessionConfig->setOptions($Config['session']);
$SessionManager = new SessionManager($SessionConfig);
$SessionManager->start();
Container::setDefaultManager($SessionManager);
}
Same problem with the onBootstrap() method of the Module class. Should this code go into each module's Module class or just once into the Application's Module class?
In both cases I have tried both approaches and I even tried putting this code into both modules at once, but the only thing I was able to accomplish was to set session variables in controller's constructor and then read them in actions/methods. I wasn't able to set a session variable in one action/method and then read it in another. If I remove the lines in which I set the variables in controller's constructor, I can no longer see these variables in the session. The session just behaves like it was created and deleted each time a page is requested.
Am I missing something? Please don't link me to any resources on the internet, I have read them all and they're not really helpful.
You don't need to do any configuration to use sessions in Zend Framework 2. Sure, you can change settings, but if you just want to get up and running with sessions, then don't worry about it for now.
My apologies, but I am going to disregard your last sentence; about a month ago, I wrote an article about this subject with the purpose of showing how to quickly get started with using sessions in ZF2. It doesn't rank well in search engines, so chances are you haven't read it.
Here is a code snippet showing how it can be done. If you are interested in how it works behind the scenes, then please refer to the link above.
namespace MyApplication\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Session\Container; // We need this when using sessions
class UserController extends AbstractActionController {
public function loginAction() {
// Store username in session
$userSession = new Container('user');
$userSession->username = 'Andy0708';
return $this->redirect()->toRoute('welcome');
}
public function welcomeAction() {
// Retrieve username from session
$userSession = new Container('user');
$username = $userSession->username; // $username now contains 'Andy0708'
}
}
about session
Where do you want to store session (in mysql-db, in mongo-db,or in ram,..)?
How to classify session into "namespace" like
$_SESSION["namespace"]["user"],
$_SESSION["namespace_1"]["user"]?
SessionManager
in Zend, Zend\Session\SessionManger help you to do many as what listed above
simple config for SessionManger
$sessionManager = new SessionManager();
$sessionStorage = new SessionArrayStorage();
$sessionManager->setStorage($sessionStorage);
//you can add more config, read document from Zend
$sessionContainer = new Container("ABC", $sessionManager);
$sessionContainer->offsetSet("user", "lehoanganh25991");
when you call new Container without any SessionManager config
$sessionContainer = new Container("abc");
behind the scence, Zend create a default SessionManager, then pass it into Container
SessionArrayStorage, $_SESSION
SessionArrayStorage in Zend can work with $_SESSION, we can access to user above through
$_SESSION["ABC"]["user"]
if you set other storages like mysql-db, mongo-db, in ram,..
access through $_SESSION may not work
access session
in Module A, set session
How can we access it in Moudle B? where $sessionContainer variable ##?
it quite weird, but when you want to access to the this container, create a new one with SAME CONFIG
$sessionManager = new SessionManager();
$sessionStorage = new SessionArrayStorage();
$sessionManager->setStorage($sessionStorage);
$sessionContainer = new Container("ABC", $sessionManager);
//access
var_dump("get user from \$sessionContainer", $sessionContainer->offsetGet("user"));
review demo on github: https://github.com/hoanganh25991/zend-auth-acl/tree/d0a501e73ac763d6ef503bbde325723ea1868351
(through commits, the project changed, access it at this tree)
in FronEnd\Controller\IndexController
in AuthAcl\Module.php
in AuthAcl\Service\SimpleAuth
i acces same session at different places
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Session\Container;
class IndexController extends AbstractActionController
{
// set session values
public function indexAction()
{
$session = new Container('User'); // name your session here by replacing User
$user_session->offsetSet('user_name', "your user name"); // set your session user name
$user_session->offsetSet('user_id', "1232"); //set your session user id
}
// function to get values from session
public function getdataAction(){
$session = new Container('User');
$user_name= $user_session->offsetGet('user_name'); // get user name from the session
$user_id= $user_session->offsetGet('user_id'); // get user id from the session
}
// function to unset session values
public function unsetdataAction(){
$session = new Container('User');
$user_session->offsetUnset('user_name'); // unset user name
$user_session->offsetUnset('user_id');
}
}

Non-public accessible function in CakePHP

I have built a simple Notification system in my Cake app that I want to have a function that will create a new notification when I call a certain method. Because this is not something the user would actually access directly and is only database logic I have put it in the Notification model like so:
class Notification extends AppModel
{
public $name = 'Notification';
public function createNotification($userId, $content, $url)
{
$this->create();
$this->request->data['Notification']['user_id'] = $userId;
$this->request->data['Notification']['content'] = $content;
$this->request->data['Notification']['url'] = $url;
$result = $this->save($this->request->data);
if ($result)
{
$this->saveField('datetime', date('Y-m-d H:i:s'));
$this->saveField('status', 0);
}
}
}
And then whenever I want to create a notification within my app I just do:
$this->Notification->createNotification($userId,'Test','Test');
However this doesn't work! The controller is talking to the model fine, but it doesn't create the row in the database... I'm not sure why... but it would seem I'm doing this wrong by just doing all the code in the model and then calling it across the app.
Edit: Based on answers and comments below, I have tried the following the code to create a protected method in my notifications controller:
protected function _createNotification($userId, $content, $url)
{
$this->Notification->create();
$this->request->data['Notification']['user_id'] = $userId;
$this->request->data['Notification']['content'] = $content;
$this->request->data['Notification']['url'] = $url;
$result = $this->save($this->request->data);
if ($result)
{
$this->saveField('datetime', date('Y-m-d H:i:s'));
$this->saveField('status', 0);
}
}
Now the thing that is stumping me still (apologies if this is quite simple to others, but I have not used protected methods in CakePHP before) is how do I then call this from another controller? So for example If have a method in my PostsController and want to create a notification on successful save, how would I do this?
I thought about in my PostsController add method:
if($this->save($this->request-data){
$this->Notification->_createNotification($userId,'Test','Test');
}
But being protected I wouldn't be able to access the method from outside of the NotificationsController. Also I'm using the same syntax as if I was calling a function from a model so again it doesn't feel right.
Hopefully someone can help me out and get me back on track as this is a new area to me.
the controller should pass all data to the model
$this->createNotification($this->request->data);
the model then can use the data:
public function createNotification(array $data) {
$key = $data[$this->alias]['key'];
$data[...] = ...;
$this->create();
return $this->save($data);
}
you never ever try to access the controller (and/or its request object) from within a model.
you can also invoke the method from other models, of course:
public function otherModelsMethod() {
$this->Notification = ClassRegistry::init('Notification');
$data = array(
'Notification' => array(...)
);
$this->Notification->createNotification($data);
}
and you can make your methods verbose, but that usually makes it harder to read/understand/maintain with more and more arguments:
public function createNotification($userId, $content, $url) {
$data = array();
// assign the vars to $data
$data['user_id'] = $userId;
...
$this->create();
return $this->save($data);
}
so this is often not the cake way..
Methods in a model are not "publicly accessible" by definition. A user cannot call or invoke a method in a model. A user can only cause a controller action to be initiated, never anything in the model. If you don't call your model method from any controller, it's never going to be invoked. So forget about the "non-public" part of the question.
Your problem is that you're working in the model as if you were in a controller. There is no request object in a model. You just pass a data array into the model method and save that array. No need for $this->request. Just make a regular array(), put the data that was passed by the controller in there and save it.
The whole approach is totally wrong in the MVC context IMO and screams for the use of the CakePHP event system. Because what you want is in fact trigger some kind of event. Read http://book.cakephp.org/2.0/en/core-libraries/events.html
Trigger an Event and attach a global event listener that will listen for this kind of events and execute whatever it should do (save something to db) when an event happens. It's clean, flexible and extendible.
If you did a proper MVC stack for your app most, if not all, events aka notifications should be fired from within a model like when a post was saved successfully for example.
This is what I have ended up doing. While it certainly isn't glamorous. It works for what I want it to do and is a nice quick win as the notifications are only used in a few methods so I'm not creating a large amount of code that needs improving in the future.
First to create a notification I do the following:
$notificationContent = '<strong>'.$user['User']['username'].'</strong> has requested to be friends with you.';
$notificationUrl = Router::url(array('controller'=>'friends','action'=>'requests'));
$this->Notification->createNotification($friendId,$notificationContent,$notificationUrl);
Here I pass the content I want and the URL where the user can do something, in this case see the friend request they have been notified about. The url can be null if it's an information only notification.
The createNotification function is in the model only and looks like:
public function createNotification($userId, $content, $url = null)
{
$this->saveField('user_id',$userId);
$this->saveField('content',$content);
$this->saveField('url',$url);
$this->saveField('datetime', date('Y-m-d H:i:s'));
$this->saveField('status', 0);
}
This creates a new record in the table with the passed content, sets its status to 0 (which means unread) and the date it was created. The notification is then set as read when a user visits the notifications page.
Again this is most probably not an ideal solution to the problem outlined in this question... but it works and is easy to work with And may prove useful to others who are learning CakePHP who want to run functions from models when building prototype apps.
Remember nothing to stop you improving things in the future!
First of all, you can improve your last solution to do one save() (instead of 5) the following way:
public function createNotification($userId, $content, $url = null){
$data = array(
'user_id' => $userId,
'content' => $content,
'url' => $url,
'datetime' => date('Y-m-d H:i:s'),
'status' => 0
);
$this->create();
$this->save($data);
}
When I began programming CakePHP(1.3) more than a year ago I also had this problem.
(I wanted to use a function of a controller in any other controller.)
Because I didn't know/researched where to place code like this I've done it wrong for over a year in a very big project. Because the project is really really big I decided to leave it that way. This is what i do:
I add a function (without a view, underscored) to the app_controller.php:
class AppController extends Controller {
//........begin of controller..... skipped here
function _doSomething(){
//don't forget to load the used model
$this->loadModel('Notification');
//do ur magic (save or delete or find ;) )
$tadaaa = $this->Notification->find('first');
//return something
return $tadaaa;
}
}
This way you can access the function from your Notification controller and your Posts controller with:
$this->_doSomething();
I use this kind of functions to do things that have nothing to do with data submittance or reading, so i decided to keep them in the app_controller. In my project these functions are used to submit e-mails to users for example.. or post user actions to facebook from different controllers.
Hope I could make someone happy with this ;) but if you're planning to make a lot of these functions, it would be much better to place them in the model!

Zend_Session: determine if Session was initially started or just updated

I've got a problem with Zend_Session. I need to know, if the Session for this user was initially started the first time or if it was just updated in the current request.
I need to know that for statistics. If the session was initialized (meaning the user visits my app for the first time) I want to store the referer of the request in some db-table. This of course I only want to do for the first request within this session.
The manual talks about the methods Zend_Session::isStarted() and Zend_Session::sessionExists(). But it seems that both methods only work for within the current request (meaning it returns true if I use Zend_Session::start() somewhere in my app).
My approach was the following:
I tried to override Zend_Session::start() to insert the statistic-data into my db-table.
// Somewhere in my bootstrap:
My_Session::start();
// This is my class (eased up)
class My_Session extends Zend_Session
{
public static function start($options)
{
parent::start($options);
if(/* Here I need the condition to test, if it was the initial session-starting... */)
{
$table = new Zend_Db_Table(array('name' => 'referer'));
$row = $table->createRow();
$row->url = $_SERVER['HTTP_REFERRER'];
$row->ip = $_SERVER['REMOTE_ADDR'];
// ... some columns ...
$row->save();
}
}
}
Anybody has any idea?
I need to know, if the Session for this user was initially started the first time or if it was just updated in the current request.
Not a problem:
Zend_Session::start();
$my_logger = new Zend_Session_Namespace('my_logger');
if(isset($my_logger->has_already_visited_app) && $my_logger->has_already_visited_app) {
// this is not the first request
} else {
// this is the first request, do something here
// make sure to add the following
$my_logger->has_already_visited_app = true;
}

Categories