I am working on a web application that lets users login and give an exam scheduled by the admin. I have an "accumulate" function that should run automatically once all the users have finished giving the test and update the database (according to some logic).
I know I can use the database to keep a store of users who are giving the test right now and accordingly run the logic but I am interested in knowing if this can be done by a singleton class.
My code:
class ScoreBoard{
var $current;
private static $board=NULL;
// private static $current=0;
private function __construct() {
$this->current=0;
}
static function scoreboard(){
if(!self::$board){
self::$board= new ScoreBoard();
$this->log("Created new");
// return self::$board;
}
return self::$board;
}
function add(){
$this->current+=1;
$this->log("add ".$this->current);
}
function subtract(){
$this->current-=1;
$this->log("subtract ".$this->current);
// file_put_contents("scoreboard.txt",self::$current);
if($this->current<0)
$this->current=0;
if($this->current<=0)
{
$this->accumulate();
self::$board=NULL;
}
}
}
And in the startExam.php file I am calling this function as :
$scoreboard= ScoreBoard::scoreboard();
$scoreboard->add();
And doing
$scoreboard= ScoreBoard::scoreboard();
$scoreboard->subtract();
when the exam ends. Thus, when each user starts the exam the singleton objects add function should be called and when he ends it the subtract function should be called. But this doesn't seem to work for some reason and the $current never increases beyond 1.
Kindly let me know if what I am trying to do is possible or not. And if there are any better ways to achieve what I want to do.Thank you.
You could use Memcached to achieve this -
Your constructor function would then look something like this:
$this->memcache = new Memcached();
$this->memcache->addServer("127.0.0.1", "11211") // I think that's the right port for default.
$this->current = $this->memcache->get("current");
But you could do the same logic via storing the value in a file - and that would be easier...
Related
Edit: This question is more about how to create a contract within a function. How do I create methods that do simple things and have requirements between objects? Do I:
1) Add checks and exceptions in the start() method to create the contract and put the pausing loop in a different call? (Downside here is a minor repeat call to the data source.)
2) Add an event listener for whenever a timer is started to create the contract? (I'm not sure I can return data the way I would like with this method. I'm also not sure I can guarantee that the event will complete successfully before I start the new timer. May not matter that much in this case.)
3) Just return the ids from the start function and process them. (The function will be doing too much, but at least it will work properly with less overhead.)
========================================================================
I have this code in my model. This is a timer application and this code gets hit when starting a timer. Basically, any running timers should get paused and somehow the view needs to understand that it should refresh those timers.
public function start($input = array())
{
if($timers = TimeLog::where('status','running')->get()){
foreach($timers as $timer){
/** #var $timer TimeLog **/
$timer->pause();
}
}
$this->user_id = Auth::user()->id;
$this->addDetails($input);
$this->restarted_at = date('Y-n-d H:i:s'); //TODO timezones
$this->status = 'running';
$this->save();
}
I'm uncomfortable returning a list of paused timers from this function. Just doesn't seem to make sense.
I thought about moving the foreach to my controller, but this is really business logic and I wanted to make sure no running timers exist when I start a timer.
I could make another method in this class, which would solve the return issue, but then how do I guarantee that each start call will check for running timers?
This seems like a good fit for using the repository pattern as described here.
I recently had to solve a similar problem since I am just getting started with Laravel and I was putting all my business logic in either Model or Controller classes. I had business logic that didn't seem to make sense for either of those, and after some research I found Repositories.
I would try something like this:
class EloquentTimerRepository implements TimerRepository
{
/**
* Part of your TimerRepository interface
*/
public function startTimersForCurrentUser($inputs)
{
$this->pauseRunningTimers();
$newTimer = $this->createNewTimer($inputs);
$newTimer->start();
}
private function createNewTimer($inputs)
{
$timer = new Timer;
$timer->user_id = Auth::user()->id;
$timer->addDetails($input);
$timer->save();
return $timer;
}
private function getRunningTimers()
{
return TimeLog::where('status','running');
}
private function pauseRunningTimers()
{
if($this->getRunningTimers()){
foreach($timers as $timer){
/** #var $timer TimeLog **/
$timer->pause();
}
}
}
}
and then:
class Timer extends Model
{
public function start()
{
$this->restarted_at = date('Y-n-d H:i:s'); //TODO timezones
$this->status = 'running';
$this->save();
}
}
As for updating the view, you're going to have to either do a page reload or if you are using ajax, make a subsequent call to pull the latest timers and reset the page elements based on that data. There are probably ways to implement push (from the server) but I'm not familiar with those techniques yet.
Through my multiple studies I have come across the factory method of setting session and database objects which I have been using while in development. What I am wondering is, putting aside personal preference (although I will soak in any opinions anyone has), does this general method work, and is it efficient (meaning, am I using it correctly)? If it is not, do you have suggestions for how to improve it?
Background
I created the code this way so as to pass a database and session object to the class upon calling the class. I wanted to be able to pass along the relevant objects/references so that they could be used.
The Call Class
This class is meant to call static functions, like so:
class CALL {
public static $_db, $_session;
public status function class1() {
$function = new class1();
$function->set_session(self::$_session);
$function->set_database(self::$_db);
return $function;
}
public status function class2() {
...
}
...
}
The _set class
class _set {
public $_db, $_session;
public function __construct() { ... }
public function set_database($_db) {
$this->_db = $_db;
}
public function set_session($_session) {
$this->_session = $_session;
}
}
Now the classes referenced.
class class1 extends _set {
function __construct() { ... }
function function1() { return "foo"; }
...
}
So, moving forward, the classes would be called using CALL::class1 or CALL::class2. After that, they can be accessed as per usual, aka:
CALL::$_db = $database->_dbObject;
CALL::$_session = $_SESSION;
$class1 = CALL::class1;
echo $class1->function1(); //prints "foo".
Read about Dependency Injection . Small suggestion from my point of view, you should never create objects like $db or $session inside other objects. You should rather inject them through constructor or setter method. It will make your code less dependant on a specific classes and it will be easier to replace all dependencies almost without refactoring (actually without one if you know hot to use interfaces).
If anyone stumbles on this, I will share with you what my solution was.
Although this exercise helped me to learn a lot, and I am sure I could take the time to create a VERY highly functional factory/Container, because this is not integral to my program and not even unique, I finally bowed to the age old wisdom of not repeating something that has already been done.
I utilized Pimple, a lightweight library that uses PHP closures to create function calls. Now, I can haave the flexibility of determining which dependency injections I want, but I also only need to inject them once. Future calls, even when they create new instances, will replicate them. While I think that, in theory, my project was workable as it was, it did indeed have the unfortunate issue of requiring you to go into the container to make changes. With Pimple I do not need to do that. So I've tossed by Container class and picked up a lightweight program from the maker of Symfony. While this may not be the best answer for everyone, it was for me. Cheers!
I have the following Singleton Class in PHP.
class CounterBalance{
private static $instance;
private $counterBalance;
private function __construct(){
$this->counterBalance = mt_rand(1, 4);
}
// Getter method for creating/returning the single instance of this class
public final static function getInstance() {
if(!self::$instance) {
self::$instance = new CounterBalance();
echo "CounterBalance constructed <br/>";
}
return self::$instance;
}
public function getCounterBalanceValue() {
return $this->counterBalance;
}
}
But in the class when I do something like
CounterBalance::getInstance()->getCounterBalanceValue();
on the same php page, it works properly. But it not working properly across pages. I get more than one instance of CounterBalance, when I do the same function call in the subsequent php page.
Can anyone one please explain why this happens.
Thanks in advance.
Welcome to the stateless world of HTTP.
A singleton can only persist for the single page load (or any other PHP data structure, for that matter). When the php process dies, the singleton dies with it. The next time a page is loaded the singleton is created all over again. The singleton is only alive in the context of that single process. If you tried to create ten instances of it during a single script execution you would maintain the single instance.
If you need data persistence across pages you'll have to implement an agent of state. For example, the $_SESSION or $_GET superglobals or store data in a database (for example) and re-retrieve it on subsequent page loads.
The following is an excerpt from some code I wrote to assign the $user->privilege based on a method from that same class. It seems excessively repetitive, and I am wondering if there is something I can do to make it more readable -- given that I haven't seen this kind of repetition too much in codes I have looked at.
$user -> privileges = $user -> get_privileges ( $user -> username );
It doesn't look particularly repetitious to me, but it is a little unusual to be assigning an object's property based on a method outside the class. Instead, this might be better handled inside the object constructor, eliminating the need for you to remember to set the property when coding:
class User {
public $username;
public $privileges;
public function __construct() {
// setup the user however that's done...
// And assign privileges in the constructor
$this->privileges = $this->get_privileges();
}
// In get_privilegs, rather than passing the username property,
// just access it via $this->username.
// Unless you need to use this method from time to time outside the class, it can be private
private function get_privileges() {
// Get privs for $this->username
}
}
And as an alternative to $this->privileges = $this->get_privileges(); called in the constructor, you might just set $this->privileges inside the get_privileges() method. Then you can just call it as $this->get_privileges() in the constructor, no assignment necessary. Either way works.
I use this pattern a lot when a method is expensive and I can just store the result for the remainder of the request:
class User {
protected $_privileges = null;
public function getPrivileges() {
if ($this->_privileges == null) {
// code to populate privileges array
$this->_privileges = $privileges;
}
return $this->_privileges;
}
}
That way getPrivileges() will only do the hard work once and afterward it uses its own locally cached copy for the remainder of the request for that object instance.
I have a session class that basicly just sets and retrieves session variables,
the reason I made it was so I could easily change it to use sessions or something
like memcache to set the items and have them accessible on multiple pages without hitting the database
I then have this user class which uses the session object to get session variables in it.
I am wanting to add to this user class though, to make it more encapsulated I would like to be able to set the variables that I am retrieving in this class
so right now I can display the userid with $user->userid; I would like to first have a method or something that sets its value from the session object I guess
Does this sound lke a good idea or possibly a lot of overhead?
And if what I am trying to do is a good idea maybe you could suggest/show example of how I should do it? I am thinking that if I add that method in that possibly I should move the code in the __construct method into it's own method
Basicly, I have the variables listed in the top part of the class that are used in the construct method, if I have multiple methods in the class though would I need to set them all at the top like that?
<?PHP
//user.class.php file
class User
{
public $userid;
public $name;
public $pic_url;
public $gender;
public $user_role;
public $location_lat;
public $location_long;
public $newuser;
function __construct()
{
global $session;
if($session->get('auto_id') != ''){
//set user vars on every page load
$this->userid = $session->get('auto_id'); //user id number
$this->name = $session->get('disp_name');
$this->pic_url = $session->get('pic_url');
$this->gender = $session->get('gender');
$this->user_role = $session->get('user_role');
$this->location_lat = $session->get('lat');
$this->location_long = $session->get('long');
$this->newuser = $session->get('newregister');
}else{
return false;
}
}
}
//with the class above I can easily show some user variables I have saved into a session like this below
$user = new user();
$user->userid;
?>
In general your idea is a good one
3 things I would do differently:
1) In your implementation doesn't seem to consider having several users. ie Several instances of the same class.
2) I would use factories instead of using IF in the constructor.
So for a user you have saved in the session you would call:
$savedUser = User::fromSession($userId);
for a new user
$user = new User()
3) Use the serialize and unserialze functions to save that data to the session
Then your class could could be implemented as
public static function fromSession($userId) {
return unserialize($session->get('users_'.$userId));
}
public function save() {
return $session->set('users_'.$this->id , serialize($this));
}
I guess this is vaguely an answer to the "is this a good idea" question. In my understanding, locating variables in the session versus refreshing them from the database is a question of the trade off between complex queries and deserializing data. The session data isn't a free magic cache that escapes database calls, it is just a convenient wrapper around a database call that you don't have to deal with. Any variable that you place in the session must be serializable. The whole collection of serialized data is then managed; the server fetches the data using the session key, deserializes it all, and hands it to the php script. Then when it closes the session for that request-response cycle it serializes it all and puts it back in the db.
So the mess in dealing with all that can, in some cases, be worse than the mess of just opening a connection and asking the db for the same stuff (or a subset of stuff) directly.
I would say that putting one or two key values in the session is a good stopping place, and relying on it too heavily for statefulness is a less-optimal plan.
I would set a new session with a name like "ValuesInSession" to true or false depending on whether or not you have session values for the fields in your user class. Then, in the sessions\users class you can check whether this session is true or false and set your values accordingly (IE from the existing sessions or to empty strings\0)
EDIT: You could, alternatively to putting that code in the user or sessions class, write a new class which could work with your users class to set the values properly (perhaps it could extend the sessions class?)
I'm not sure I understand the question, however, if you are using php 5, you can use the __set magic method to help with this.
Modifying your current class:
class User
{
private $id;
private $data = array();
public function __construct()
{
global $session;
$this->id = $session->get('auto_id');
$this->data = array(
'disp_name'=>$session->get('disp_name'),
'pic_url'=>$session->get('pic_url'),
'gender'=>$session->get('gender'),
'user_role'=>$session->get('user_role'),
'lat'=>$session->get('lat'),
'long'=>$session->get('long'),
'newregister'=>$session->get('newregister')
);
}
// return the user id
public function id()
{
return $this->id;
}
// the __get magic method is called when trying to retrieve a value of a
// property that has not been defined.
public function __get($name)
{
if(array_key_exists($name, $this->data))
{
return $this->data[$name];
}
return null;
}
// the __set magic method is called when trying to store a value in a property
// that has not been defined.
public function __set($name, $value)
{
global $session;
// check if the key exists in the 'data' array.
// if so, set the value in the array as well as the session
if(array_key_exists($name, $this->data))
{
$this->data[$name] = $value;
$session->set($name, $value);
}
}
}
This way you can still get and set values the same as you were, but will also store the set the value in your session class.
To test this:
$user = new User;
if($user->id())
{
echo $user->disp_name;
$user->disp_name = 'new name';
echo $session->get('disp_name');
}
I would not suggest you that because:
It is not a good practice to select an architecture "in case of future need" ('the reason I made it was so I could easily change'). Check http://www.startuplessonslearned.com (Eric Ries) or http://highscalability.com articles
Your code is hard/impossible to test (See Misko Hevery's blog (A google evangelist) http://misko.hevery.com for further information).
You are using "global" (never a good idea if you want to keep track of the dependencies).
It is better to seperate "the business logic" (a User class) and the wiring/building (a factory class for example). (See http://en.wikipedia.org/wiki/Single_responsibility_principle and "separation of concerns")
For really good code examples (and to understand which OO laws should not be broken), I can advice you Misko's blog (Also do not miss his technical talks at google that you can find on youtube). I am sure you will love them.
Hope this helps.