I need opinion about using session with php. I'm useing session to store data. For instance - configuration:
First I'm loading data from config.ini to $_SESSION['config']
Then I'm using custom session class to get specific data from $_SESSION['config'][$key];
This is config function:
public static function load_config($process_sections = FALSE)
{
$array = parse_ini_file(CONFIG . DS . 'config.ini', $process_sections);
if ($array)
{
$_SESSION['configuration'] = $array;
return TRUE;
}
else
{
$_SESSION['configuration'] = array();
return FALSE;
}
}
function config($key, $default = NULL)
{
if (isset($_SESSION['configuration']))
{
if (isset($_SESSION['configuration'][$key]))
{
return $_SESSION['configuration'][$key];
}
else
{
return $default;
}
}
}
That same is with user object. I'm getting user data not from DB, but API, and storing it in $_SESSION['user']. When user object is constructs, I'm attributing all properties just from $_SESSION['user'][...], for instance:
public function __construct()
{
parent::__construct();
$this->initUser();
}
private function initUser()
{
if (Session::is('user'))
{
return $this->setUserData(Session::get('user'));
}
else
{
return FALSE;
}
}
private function setUserData($data)
{
foreach ($data as $key => $value)
{
if(property_exists($this->_name, $key))
{
$this->{$key} = $value;
}
}
return TRUE;
}
Properties are defined in class. I'm doing it just on time, when object is constructing. Is that right practice? It's working very good for me but I doubt if my method overolads server.
Related
I am new to PHP & Codeigniter but it was needed some kind of implementation in PHP.
Following are dirty methods are provided in rails framework by default, here person is model object representing row inside persons table.
person.name = 'Bob'
person.changed? # => true
person.name_changed? # => true
person.name_changed?(from: nil, to: "Bob") # => true
person.name_was # => nil
person.name_change # => [nil, "Bob"]
person.name = 'Bill'
person.name_change # => [nil, "Bill"]
I am interested in to & from specially, Please suggest whether it is possible with any way.
If you would consider Laravel's elquent framework you have a great deal of that functionality already.
Laravel Eloquent update just if changes have been made
It holds an array of the "original" values in the Model, and if any of them have been changed it will commit them to the database.
They also come with a lot of events you can plug into(beforeSave, afterSave, beforeCreate, afterCreate, validation rules, etc...) and they can be extended easily. It might be the closest compatible thing I can imagine you're looking for.
This is however not codeigniter, it relies on a different framework. If you're not dead set on codeigniter you might consider switching to a framework like Laravel or OctoberCMS depending on your needs.
Edit because you're stuck with codeigniter
You might wish to use a library like this one: https://github.com/yidas/codeigniter-model
It is then very easy to extend with some custom caching mechanisms.
The code below is something you could use as a basis for your own model implementation.
It has a very rudementary logic basis, but allows you to check on the dirty status and roll back any changes made to the model.
Note this this is very rudementary, and might even contain a few errors because I have not run this code. it's more a proof of concept to help you create a model that suits your needs.
class User extends CI_Model
{
public $table = 'users';
public $primaryKey = 'id';
public $attributes;
public $original;
public $dirty = [];
public $exists = false;
function __construct()
{
parent::Model();
}
public static function find($model_id)
{
$static = new static;
$query = $static->db->query("SELECT * FROM ' . $static->getTable() . ' WHERE ' . $this->getKeyName() . ' = ?", [$model_id]);
if($result->num_rows()) {
$static->fill($query->row_array());
$static->exists = true;
}
else {
return null;
}
return $static;
}
public function getKeyName()
{
return $this->primaryKey;
}
public function getKey()
{
return $this->getAttribute($this->getKeyName());
}
public function getTable()
{
return $this->table;
}
public function fill($attributes)
{
if(is_null($this->original)) {
$this->original = $attributes;
$this->dirty = $attributes;
}
else {
foreach($attributes as $key => $value) {
if($this->original[$key] != $value) {
$this->dirty[$key] = $value;
}
}
}
$this->attributes = $attributes;
}
public function reset()
{
$this->dirty = [];
$this->attributes = $this->original;
}
public function getAttribute($attribute_name)
{
return array_key_exists($attribute_name, $this->attributes) ? $this->attributes[$attribute_name] : null;
}
public function __get($key)
{
return $this->getAttribute($key);
}
public function __set($key, $value)
{
$this->setAttribute($key, $value);
}
public function setAttribute($key, $value)
{
if(array_key_exists($key, $this->original)) {
if($this->original[$key] !== $value) {
$this->dirty[$key] = $value;
}
}
else {
$this->original[$key] = $value;
$this->dirty[$key] = $value;
}
$this->attributes[$key] = $value;
}
public function getDirty()
{
return $this->dirty;
}
public function isDirty()
{
return (bool)count($this->dirty);
}
public function save()
{
if($this->isDirty()) {
if($this->exists)
{
$this->db->where($this->getKeyName(), $this->getKey());
$this->db->update($this->getTable(), $this->getDirty());
$this->dirty = [];
$this->original = $this->attributes;
}
else
{
$this->db->insert($this->getTable(), $this->getDirty());
$this->dirty = [];
$this->original = $this->attributes;
$this->attributes[$this->getKeyName()] = $this->db->insert_id();
$this->original[$this->getKeyName()] = $this->getKey();
$this->exists = true;
}
}
}
}
if($user = User::find(1)) {
$user->name = "Johnny Bravo";
$user->save();
}
Say I have to similar function :
public function auth(){
return $someResponse;
}
public function collect(){
return $someOtherResponse
}
Question : When one of the response get passed to another class, is there any way to check which function returned the response ?
In a purely object-oriented way, wanting to attach information to a value is akin to wrapping it into a container possessing context information, such as:
class ValueWithContext {
private $value;
private $context;
public function __construct($value, $context) {
$this->value = $value;
$this->context = $context;
}
public value() {
return $this->value;
}
public context() {
return $this->context;
}
}
You can use it like this:
function auth()
{
return new ValueWithContext($someresponse, "auth");
}
function collect()
{
return new ValueWithContext($someotherrpesonse, "collect");
}
This forces you to be explicit about the context attached to the value, which has the benefit of protecting you from accidental renamings of the functions themselves.
As per my comment, using arrays in the return will give you a viable solution to this.
It will allow a way to see what has been done;
function auth()
{
return (array("auth" => $someresponse));
}
function collect()
{
return (array("collect" => $someotherrpesonse));
}
class myClass
{
function doSomething($type)
{
if (function_exists($type))
{
$result = $type();
if (isset($result['auth']))
{
// Auth Used
$auth_result = $result['auth'];
}
else if (isset($result['collect']))
{
// Collect used
$collect_result = $result['collect'];
}
}
}
}
It can also give you a way to fail by having a return array("fail" => "fail reason")
As comments say also, you can just check based on function name;
class myClass
{
function doSomething($type)
{
switch ($type)
{
case "auth" :
{
$result = auth();
break;
}
case "collect" :
{
$result = collect();
break;
}
default :
{
// Some error occurred?
}
}
}
}
Either way works and is perfectly valid!
Letting the two user defined functions auth() & collect() call a common function which makes a call to debug_backtrace() function should do the trick.
function setBackTrace(){
$backTraceData = debug_backtrace();
$traceObject = array_reduce($backTraceData, function ($str, $val2) {
if (trim($str) === "") {
return $val2['function'];
}
return $str . " -> " . $val2['function'];
});
return $traceObject;
}
function getfunctionDo1(){
return setBackTrace();
}
function getfunctionDo2(){
return setBackTrace();
}
class DoSomething {
static function callfunctionTodo($type){
return (($type === 1) ? getfunctionDo1() : getfunctionDo2());
}
}
echo DoSomething::callfunctionTodo(1);
echo "<br/>";
echo DoSomething::callfunctionTodo(2);
/*Output
setBackTrace -> getfunctionDo1 -> callfunctionTodo
setBackTrace -> getfunctionDo2 -> callfunctionTodo
*/
The above function would output the which function returned the response
I have a Project class/object that needs to have (own) an uncertain number of Phase objects.
I don't know the number of phases the project object will have when it is created, so I didn't want to put Phase object creation in the constructor function of Project.
My classes:
class Project {
//some properties
}
class Phase {
public $property;
}
And I'd like to do this:
$foo = $myProject->phase01->property;
$bar = $myProject->phase06->property;
//etc...
I wouldn't use dynamic properties.
If the phases are a collection, would treat them as such, it could come handy later on. E.g.:
class Project {
private $phases = [];
public function __get($property)
{
// if begins with "phase" and some number
if ( preg_match("/^phase(\d+)$/", $property, $matches) ) {
// if is set already, we return it
if ( isset($this->phases[$matches[1]]) ) {
return $this->phases[$matches[1]];
}
// if it isn't, it isn't :)
return null;
}
}
public function __set($property, $value)
{
if ( preg_match("/^phase(\d+)$/", $property, $matches) ) {
$this->phases[$matches[1]] = $value;
}
}
public function addPhase(Phase $phase, $phase_number = null)
{
if ($phase_number !== null) {
$this->phases[$phase_number] = $phase;
}
else {
$this->phases[] = $phase;
}
return $this;
}
public function getPhases()
{
return $this->phases;
}
// etc
}
class Phase {
public $property = "";
public function __construct($property) {
$this->property = $property;
}
}
$myProject = new Project();
$myProject->phase1 = new Phase('startup');
$myProject
->addPhase(new Phase('build'))
->addPhase(new Phase('cleanup'));
foreach ($myProject->getPhases() as $key => $phase) {
echo "Phase $key: {$phase->property}", "\n";
}
You could implement one of php's magic methods, in particular __get
<?php
class Project {
//some properties
public function __get($property)
{
// if begins with "phase" and some number
if ( preg_match("/^phase\d+$/", $property) === 1 ) {
if ( !isset($this->$property) ) {
$this->$property = new Phase;
}
return $this->$property;
}
}
}
class Phase {
public $property;
}
$myProject = new Project;
//And I'd like to do this:
$foo = $myProject->phase01->property;
$bar = $myProject->phase06->property;
//etc...
What are the implications of
// Use a setData method to populate data on the object. This will allow data to be set multiple times with a single object
class Testy
{
private $data = [];
public function setData(array $data)
{
$this->data = $data;
}
public function validate()
{
foreach($this->data as $data) {
if (! isset($data['id'])) {
return false;
}
}
return true;
}
}
versus
// Set data using the constructor that will require multiple objects to handle multiple use cases
class Testy
{
private $data = [];
public function __construct(array $data)
{
$this->data = $data;
}
public function validate()
{
foreach($this->data as $data) {
if (! isset($data['id'])) {
return false;
}
}
return true;
}
}
versus
// Set data to be validated directly on the validate method. This is the most concise of the 3 but the class simply becomes a wrapper for the method which may be a smell that it belongs elsewhere.
class Testy
{
public function validate($data)
{
foreach($data as $data) {
if (! isset($data['id'])) {
return false;
}
}
return true;
}
}
To provide some context: the example is very simplified and each $data array will contain objects used for validation. I wanted to know in a scenario where this object might be used several times in a given request, which of the examples would be considered better and if there are any implications of any of the approaches listed.
I'm porting to PHP a piece of Java code that uses a lot of Bi-directional maps (Guava's BiMap). Java-like maps are provided by PHP arrays or SplObjectStorage, but is there a library PHP Bi-Directional map available?
This class should provide for most needs of a bi-directional map :
class BiMap
{
private $KtoV, $VtoK;
public function __constructor()
{
$this->KtoV = []; // for version < 5.4.0, syntax must be: $this->KtoV = array();
$this->VtoK = [];
}
public function getKey($v)
{
if($this->hasValue($v))
{
return $this->VtoK[$v];
}
else
{
return null;
}
}
public function getAllKeys()
{
if($this->KtoV)
{
return array_keys($this->KtoV);
}
else
{
return $this->KtoV;
}
}
public function getValue($k)
{
if($this->hasKey($k))
{
return $this->KtoV[$k];
}
else
{
return null;
}
}
public function getAllValues()
{
if($this->VtoK)
{
return array_keys($this->VtoK);
}
else
{
return $this->VtoK;
}
}
public function hasKey($k)
{
return isset($this->KtoV[$k]);
}
public function hasValue($v)
{
return isset($this->VtoK[$v]);
}
public function put($k, $v)
{
if($this->hasKey($k))
{
$this->removeKey($k);
}
if($this->hasValue($v))
{
$this->removeValue($v);
}
$this->KtoV[$k] = $v;
$this->VtoK[$v] = $k;
}
public function putAll($array)
{
foreach($array as $k => $v)
{
$this->put($k, $v);
}
}
public function removeKey($k)
{
if($this->hasKey($k))
{
unset($this->VtoK[$this->KtoV[$k]]);
$v = $this->KtoV[$k];
unset($this->KtoV[$k]);
return $v;
}
else
{
return null;
}
}
public function removeValue($v)
{
if($this->hasValue($v))
{
unset($this->KtoV[$this->VtoK[$v]]);
$k = $this->VtoK[$v];
unset($this->VtoK[$v]);
return $k;
}
else
{
return null;
}
}
}
However, if you require null checking for key/values and/or object/array checking then handling similar to the following lines of code should be given in the body of a function and called appropriately within the hasKey($k), hasValue($v) and put($k, $v) methods :
if($item === null)
{
throw new Exception('null as BiMap key / value is invalid.');
}
if(is_object($item) || is_array($item))
{
throw new Exception('Object / Array as BiMap key / value is invalid.');
}
I did that once putting the values into 2 arrays. If keySet() and valueSet() are disjunct you can even use one value. Example:
$mapKtoV = array();
$mapVtoK = array();
function putInMap ($key,$value)
{
$mapKtoV[$key] = $value;
$mapVtoK[$value] = $key;
}
Of course you can also put them into a class.
Do you also think that this solution appears dodgy and smells? Yes, true, welcome to the world of PHP, which is usually dominated by bad code design. If you are really looking for a good solution, you should actually port you source from PHP to Java ;)
Hope it helps.