I have a strange problem I can't seem to track down.
I have a custom class ("Person") extending Zend_Db_Table_Row_Abstract that represents a user.
Among other things, this class has custom variables that are set in the init() method, for instance:
class Person extends Zend_Db_Table_Row_Abstract
{
protected $_cdata = array(); // non-db-table data gets put here through __set()
public function init()
{
$this->fullName = $this->firstName." ".$this->lastName; // this is saved to $this->_cdata['fullName']
}
Upon login, I store an object of this class as Zend Auth Identity:
$r = $auth->authenticate($authAdapter);
if($r->isValid())
{
$user = $db->getUserByEmail($email); // Retrieves an object of class "Person"
$auth->getStorage()->write($user);
}
Now, if I call Auth Identity in the same action request as the login, it will work alright:
echo $user->fullName; // Will print "John Smith" or whatever it is
However, when I call another action, and call Auth Identity, I lose whatever I have stored in "_cdata" array:
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity() {
$user = $auth->getIdentity();
echo $user->fullName; // Prints nothing...$_cdata['fullName'] does not exist.
}
Any ideas?
The reason why that's happening is because Zend_Auth identity data gets serialized (and deserialized) between requests.
Which leads us to a closer look onto __sleep method of Zend_Db_Table_Row_Abstract class, which is the one that gets called once $user object is serialized.
public function __sleep()
{
return array('_tableClass', '_primary', '_data', '_cleanData', '_readOnly' ,'_modifiedFields');
}
What you need to do is to override this method in your Person class, so that it includes $_cdata array as well. Then this property will be serialized and available in the next HTTP request.
Related
I have the following class for all my user methods:
class User {
protected $_db,
$_data;
public function __construct($user = null, $findby = 'id') {
$this->_db = DB::getInstance();
if (!$user) {
........
} else {
........
}
}
.......
public function login($username = null, $password = null) {
$user = $this->find($username, 'username');
if ($user) {
$lockdown = new Lockdown;
}
}
public function find($param = null, $method = null) {
if ($param && $method) {
$data = $this->_db->query("SELECT * FROM users ...");
if ($data->count()) {
$this->_data = $data->result();
return true;
}
}
return false;
}
public function data() {
return $this->_data;
}
}
The above is a completely stripped down version of my user class. I also have another class (lockdown) which extends user:
class Lockdown extends User {
public $getAttempts;
public function __construct() {
var_dump($this->data());
die();
}
}
However when i call the lockdown class inside of the login class, even though the data object should contain all the user information, the var_dump() is simply returning NULL.
From my calculations when the login class is called, the find method should set $_data = USER INFO, which should therefore allow the new Lockdown method invoked just after the ($this->find()) to be able to access the same data method.
I am still learning OOP Programming so don't know if there is something i am missing, but i can't seem to understand the reason as to why the Lockdown class returns NULL on the data method when it should inherit it.
You should not put any computation logic inside a constructor. It makes it hard to test. You also cannot return from a constructor.
You structure is a complete disaster. Both because of your abuse of the inheritance and of global state.
It makes no sense for a class to create a new instance of its own child class for retrieving data. This is probably a result of you attempting to for a User class to combine two different responsibilities: persistence and business logic. This constitutes a violation of Single Responsibility Principle, which then manifest in a form of a convoluted call graph.
Also the whole class Lockdown extends User construct makes no sense. The extends keyword in OOP can be translates as "is special case of" (as per LSP). The class for tracing user's login attempts is not a specialized case of "user".
You should have at least 3 separate classes for this: one for handling the "user's behavior" and other for saving/restoring "user's state" (the approach is called "data mapper"). The third one would be for managing the the failed attempts.
I would also highly recommend watching this lecture.
As for global state, instead of using a singleton anti-pattern, you should have passed the database connection as a constructor's dependency to the class, which need to interact with persistence.
As for the code, at a high level, it should probably looks something like this:
$user = new User;
$mapper = new UserMapper($db);
$user->setName($username)
if ($mapper->fetch($user)) {
if ($user->matchPassword($password)) {
// you have logged in
// add some flag in session about it
header('Location: /greetings');
exit;
}
// check the failed attempts
} else {
// no matching username
}
I am novice in OOP programming in php and trying to understand and implement the dependency injection feature in my MVC project. In the following I am explaining a super simple example of the feature where I am struggling applying the dependency injection. The actual application is lot more complex than this, however, this should be enough to demonstrate the problem I am having.
I have created a Model called “user” that is responsible for managing a single user. Data handled by the class (data about a user) is also saved in the database table. The “user” class has method to load from and save/update the data to the database table. The user class can be initiated with data loaded from the database (by using user id) or load from the array supplied to the constructor.
The project deals with multiple users at a time. So, I have created a container class called “users”. This class has an array of “user” objects. However, this class also have method to load data for multiple user objects from the database (based on criteria such as all paid users), then create the object array with the data. The number of object is created is depends on the number of users returned from the database.
The following is a sample code for the classes
class user
{
private $data;
function __construct ($arData=””)
{
$this->dbTable ="user";
if(!is_array($ar))
{
if($ar!="")
{
$ar = $this->getDataFromDB($ar);
}
else
{
$ar = array();
}
}
$this->data = $ar;
}
function getDataFromDB($id_user){ … data base implementation … }
....
Other methods
....
}
class users // the container class
{
private $objUsers;
function __ construct(){
$this->objUsers = array();
}
function loadUsers($type){
$userDataArray = $this->getUsersFromDatabase($type);
foreach($useDataArray as $userData){
$this->objUsers[] = new user($userData);
}
}
function getUsersFromDatabase($userType) { …… database …… }
…… other methods …..
}
My concern is the container class (container may not be the right word to say). I want to know the best practice to create this type of container class and what is the recommend for this. In addition, this is clearly evident that this container class is tightly coupled with “user” class and cannot be tested separately. How can I implement the dependency injection for a class like this?
As I said, I don't think this is a good fit for dependency injection. And I wouldn't set it up that way just for the sake of saying it uses dependency injection.
The main reason it's not a good fit, is that a User is always a User. So you always have a concrete contract between the wrapper, Users, and the User. You can count on User having certain methods. And you don't have some weird 3rd class that your adding into these collections, it's just a collection of a known and well defined object.
That said, I would go with a more factory style wrapper, Where the User is the simpler of the 2 classes. ( note, I didn't test any of this, so just look at it like psudo code )
class users {
public function createUser( array $data = []){
if( $data['id'] ){
$User = $this->getUser( $data['id'] );
if( $User )
return $User;
}
//depending what you want you could search on other things
//like the email, (unique) and return the user.
//you could make this as complex, or as simple as you want
//it could simply create a new user, or check for an existing one first.
return new User($data); //dependency
}
public function getUser( $id ){
$stmt = $this->DB->prepare( "SELECT * FROM users WHERE id=:id" );
$stmt->FetchMode(PDO::FETCH_CLASS, 'User');
return $stmt->fetch(); //fetch right into the class
}
public function saveUser( User $User ){
//I just added this to show how you can type hint the class
// so that it only accepts Objects of the type User
}
}
class user{
protected $id;
protected $username;
protected $email;
public function __construct(array $data = []){
foreach( $data as $field=>$value){
//this could be done better, with error checking etc.
//but I just wanted to show how you can use the setters
//dynamically when constructing with an array
//this is useful because we are not hard coding the schema of User in any files
//-note- PHP method calls are case insensitive.
$this->set{$field} = $value;
}
}
public function setId( $id ){ $this->id = $id; }
public function getId(){ return $this->id; }
public function setUsername( $username ){ $this->username = $username; }
public function getUsername(){ $this->username; }
public function setEmail( $email ){ $this->email = $email; }
public function getEmail(){ return $this->email; }
}
Then you can worry about dependency injection for things like the Database. This could be represented by having the users constructor accept a PDO or Database object. Like this
class Users{
protected $DB;
public function __construct( $DB ){
$this->DB = $DB;
}
}
The Users class doesn't care about the DB credentials, or even the particular DB driver your using. To some extent it does have some coupling with the driver based on the SQL syntax, which may be specific to a particular database. If we wanted to make this a "truer" form of dependency injection we should use an ORM like Doctrine, or some kind of Query builder ( instead of PDO itself ). Then we would have another layer of abstraction between our code and the database.
If you need user to have access to users and they cant be separated extend the class.
class users {
}
class user extends users {
}
Child user can then access the parent users properties.
I'm building an API service and have a parent class:
classAPI {
public responseCode = "";
public responseMessageLog ="";
function run{
// here I call my user auth class
$oUser = new classUser(...);
}
}
Inside my classUser I do a bunch of stuff and then write a bunch of variables: responseMessageLog (which is running log of where the script went) and responseCode (which is set to 0 or 1 or whatever depending on success or failure or warning).
I need to access my responseCode and responseMessageLog variables from within my User class and my parent API class, but I don't really want to be passing these variables into each child class and then passing them back. I would like it that when I update the variable in the child class it updates everywhere in all my class.... kind of like a global variable would... but I know that's not a good idea.
How have others stopped passing variables down the rabbit trail of classes.
in this class I
Passing dependencies isn't a rabbit hole you want to avoid--it makes for more testable code. However, you don't need to pass every property, you can pass the parent object.
In your case just pass the classAPI object into the constructor of the classUser and in the constructor assign it to property. The classAPI properties are public so you can access them in an instance of classUser.
ClassAPI {
public $responseCode = "";
public $responseMessageLog ="";
public function run{
// here I call my user auth class
$oUser = new ClassUser($this, ...);
}
}
ClassUser {
public $myClassApi = null;
public function __construct(ClassAPI $myClassApi) {
$this->myClassApi = $myClassApi;
}
public function someFunction() {
echo $this->myClassApi->responseCode;
}
}
Added notes:
In case it comes up in another answer, don't use static properties to do what you're trying to do.
Capitalize your class names.
In production code I might add an initialization function in ClasUser instead passing the ClassAPI directly into the constructor.
I am starting to build a new project in PHP using OOP, and I have a dilemma about Object-Database relations.
For example, I have a User object. Should the constructor function already do the INSERT INTO... ? so I will call $user = new User($user_data);
Or should I have a different $user->save() method to do the INSERT?
Having a constructor perform an insert query doesn't sound like a good idea, IMHO. The User class, I think, should be regarded as a model, an object that collects data, which can be sent to a service layer. That's where the actual insert can be performed.
Just treat the User class as a type. Suppose an existing user logs in:
$login = new User(array('username' => $_POST['username'],
'pass' => $_POST['passwd']));
Then, inside the User class:
class User
{
const SALT = 'fo0bar';
private $_hash = null;
private $_name = null;
public function __construct (array $request, $login = false)
{
//this isn't the best hash in the world, of course...
$this->_hash = sha1($request['username'].SALT.$request['pass']);
$this->_name = $request['username'];
}
public function getHash()
{
return $this->_hash;
}
public function getName()
{
return $this->_name;
}
}
Nothing more than that, as far as the constructor goes. Just add more data if required, and some getters and setters. This object can then be passed to an object that has all db methods and holds the connection(s) you need, it can build a query using the hash and name getters, check if the user exists and perform an INSERT query if needed.
It will be better to use a separate 'method' for creating / saving a user.
The constructor will be executed every time you instantiate a User i.e use "user = new User()".
If inserted into your constructor a new user will be attempted to be created whenever a User object is created, which may well not be needed for the purpose you intend.
I would recommend having a separate save() function in your class for the following reasons
You have the opportunity to manipulate/amend object data before it is saved
When retrieving data, you will no doubt call $user->getAll(). So when initialising your user object, in this case - we don't want to be storing any data.
Try doing something like this
protected $_data;
public function __construct(array $data) {
$this->_data = $data;
}
public function save() {
//TODO: Save $data
return $this;
}
public function getAll() {
//TODO: Get from database and populate $this->_data
return $this->_data;
}
A common way of doing this is to separate model, and mapper. This means that User is an empty data store (model) - and you have a mapper which interacts with the object. Typical CRUD operations:
<?php
$model = new User();
$model->setName('Name');
$mapper->create($model);
$user = $mapper->find('Name');
$user->setName('NewName');
$mapper->update($user);
$model->delete($user);
Sometimes you may need to create an empty instance
php doesn't support overloading: Overloading would allow you to create a constructor which creates and empty instance.
You wouldn't want to insert an empty record for each object instance.
So I don't recommend adding an insert query to your constructor.
I'm currently improving my own MVC and I can't find a nice solution for the following scenario:
In most of my models I'm working with a few (already validated by another model) user-based inputs and need to pass them from the controller (where I basically tell the models what to do with the input) to the various models of course. At the moment I'm putting every single user input into a property:
foreach($this->properties as $property => $empty)
{
if(isset($_POST[$property]))
{
$this->properties[$property] = htmlspecialchars(trim($_POST[$property]));
}
}
Eventually when I need a new model to do something, I call it like this:
new view('calendar',$data,$this->properties);
And finally in the model I receive the input / variables by putting them in the models properties…
class validation
{
public function __construct($values)
{
foreach($values as $property => $value)
{
$this->{$property} = $value;
}
}
}
That way I never have to think about where a variable comes from (after the user input has been validated, I don't really care anymore) and can always write a for me clean to read version of $this->user_input
But I somehow have the feeling that this is not the easiest way and propably not a good one either. What bothers me the most is that when writing a new class/model, I always have to tell the model to take the input into their own property and I always have to pass parameters when calling a new class.
Is there some way where I can just inherit these variables from the user when a new class is getting called without having the controller to be a parent class - or would this actually make sense to make the controller a parent? I think it would be confusing when another controller uses the model.
Ok the big thing to remember here, is that your controller "has a" variable container (holding all your properties), as opposed to the controller being (or "is a") a variable container. So first thing, you should be using composition, and not inheritance.
The following snippets below are commented to explain in more detail. Some notes:
The InputData instance could be created above the controller level (say, in a different controller, so that is can be shared among many controllers) which answers the main part of your question. The key point is you're only writing it once, and you can safely say once it's in there, it's good to go
You can include all validation methods inside the InputData, as the role of InputData is to house/store the data safely - which in my opinion a good level of abtraction, or in other words "it's responsible for input data, if something is wrong with the input data, I know where to look"
Finally, for a little extra shine, I added some bit operations so when adding values through the input_data->add, they could be validated against multiple types (for example something could be added which needs to be validated as both a number and a post code).
index.php
require_once( "Controller.php" );
$controller = new Controller();
$controller->print_current_user();
Controller.php
<?
require_once( "Input_Data.php" );
class Controller
{
// Variables
private $input_data;
// Models
// private $model_user;
public function __construct()
{
$this->input_data = new Input_Data();
//$this->model_user = new Model_User();
// Process input (might not happen in the constructor,
// in fact, it might happen higher up, so it can be shared
// Possibly looping over GET / POST data
// for each one, add it to the inputData
$_GET[ 'name' ] = 'Chris';
$_GET[ 'country' ] = 'Australia';
// example iteration 1
$this->input_data->add( 'name', $_GET[ 'name' ], Input_Data::TYPE_VALIDATE_NAME | Input_Data::TYPE_VALIDATE_TEXT );
// example iteration 2
$this->input_data->add( 'country', $_GET[ 'country' ], Input_Data::TYPE_VALIDATE_COUNTRY );
}
// later on in controller, model needs to find the user by name
public function print_current_user()
{
// Example Usage to Model:
// $this->$model_user->get_by_name( $this->input_data->get( 'name' ) );
//
// For now, we'll settle with just printing it out
echo $this->input_data->get( 'name' );
}
}
?>
Input Data
<?
class Input_Data
{
const TYPE_VALIDATE_TEXT = 0;
const TYPE_VALIDATE_NAME = 1;
const TYPE_VALIDATE_EMAIL = 2;
const TYPE_VALIDATE_ADDRESS = 4;
const TYPE_VALIDATE_COUNTRY = 8;
protected $data;
public function __construct() {
$this->data = array();
}
public function add( $name, $value, $type )
{
if( $type & TYPE_VALIDATE_TEXT )
{
// validate input as text
// if valid, flag as such, to be inserted
// or alternatively return a safe version
// depending on your application, an empty string
}
if( $type & TYPE_VALIDATE_NAME )
{
// validate input as name
}
if( $type & TYPE_VALIDATE_EMAIL )
{
// validate input as email
}
if( $type & TYPE_VALIDATE_ADDRESS )
{
// validate input as address
}
if( $type & TYPE_VALIDATE_COUNTRY )
{
// validate input as country
}
// If its valid or is now santised
// insert into the $data variable
// if( $valid ) {
$this->data[ $name ] = $value;
// }
// data[ name ] now contains a safe value that can be accessed
}
public function get( $name )
{
// do checking to ensure it exists
// then return it
return $this->data[ $name ];
}
}
?>
Depending on your needs, it may make sense to store the user inputs in a property of a singleton class (e.g. a UserRequest class):
class UserRequest extends Singleton
{
protected $userProperties;
public function getUserProperties()
{
return $this->userProperties;
}
...other methods...
}
In your bootstrap or routing class, when you capture the user inputs, save them in your Request instance, and then have all controllers extend a base class that reads this property:
class baseController
{
protected $userProperties;
public function __construct()
{
$this->userProperties = Request::getInstance()->getUserProperties();
}
}
Then all controllers will have access to it, and you only have to capture it once.
I think a better solution is to store all the inputs in an object lets just call it data. Each of the models can have a data property. After the controller has completed input validation you can pass the object to the first model and store it there. At that point you can freely pass the object around from model to model. If you're changing values in data you should later update the controllers object with a method call like $this->data = $Model->GetData(); or whatever.
With the MVC paradigm it's not sensible to have models accessing properties of the controller. The controller should basically be initiating all communications ie the controller passes the data to the model who does operations on it, then the controller requests that data and puts it in the view. It would not be good practice to have the controller holding the data and the model operating on it directly.
What bothers me the most is that when writing a new class/model, I always have to tell the model to take the input into their own property and I always have to pass parameters when calling a new class.
So let's say you have two problems here:
Repetition to define properties per each class definition.
Passing parameters for each class creation.
In the most bare and basic sense, you can not circumvent both. If you won't tell the class (at least somehow) which properties it represents, it wouldn't know. Somewhat similar for the second point, if the data is not set to the class, it won't work.
So as it is technically not possible to prevent these two at all, the question is how to make it more comfortable and reduce repetition - if possible.
One route to go would be to just take all these objects to be of the same type. I mean actually those are just some improved arrays, aren't they?
So you can create yourself a base-class you can extend from that contains all the needed code, like importing an array, defining the properties.
So you only need to write the code once and create as many objects and different "types" as you want.
Some example, let's create one such object that has a base-class that does it's job:
class TestModel extends SelfDefinedVariableObjectBase
{
protected $properties = ['bar' => 'hello world'];
}
That's it.Object defined. Now let's use it:
// $_POST['bar'] = '<h1>test</h1> let\'s throw some HTML in';
$foo = new TestModel($_POST);
echo $foo->bar, "\n";
This does import some data from $_POST that is matching with the objects properties (similar to what you have). However the output is the same:
<h1>test</h1> let's throw some HTML in
You might now want that. So therefore you can create some decorators for example, here one that works with a callback function:
class VariableObjectCallbackDecorator
{
private $subject;
private $callback;
public function __construct(VariableObjectBase $object, callable $callback) {
$this->subject = $object;
$this->callback = $callback;
}
public function __get($name) {
return call_user_func($this->callback, $this->subject->__get($name));
}
}
Let's use it with the test-object from the previous example:
$bar = new VariableObjectCallbackDecorator($foo, 'htmlspecialchars');
echo $bar->bar, "\n";
And now this time the output is:
<h1>test</h1> let's throw some HTML in
Hope this is helpful. You can find the code here: Demo
would this actually make sense to make the controller a parent?
Yes, that is probably exactly how I would do it. Then you can use protected for the properties you want to share/inherit.