PHP Classes With Multiple Children Sharing Same Parent Instance - php

I'm having trouble getting my head around the best way to perfect my system. Currently, it's pretty archaic, so I'm interested to know if you have any suggestions about improving it?
User Class -> handles data and basic functions on users that are referenced on the page. The __construct takes an ID and uses the get_user() function to get the user's data with the given ID.
UserService (extends User) -> handles login, logout, etc. Is called at the top of every file to figure out if a user is logged in, and is defined as $user = new UserService(); every pageload, which presents the current user's data from User class.
UserNotifications (extends user) -> handles user notifications.
The problem that I'm having is that I have various child classes, such as the ones above, that interact with each other and I don't want them each calling an instance of the parent that may already be instantiated through another child.
Obviously that adds unnecessary queries. What's the best way to pass parent instances between child classes?
At this point, I'm a novice to OOP, and I've been stumped by this. I also apologise for the lack of clarity. I hope that you understand.

Related

In which model does this belong?

I often get confused as to which model to create functions. Let me try to explain my current situation with a simple made up example:
I have a Log model that contains all activities on our app. I want to get the activity for a specific user. Should I create a getActivity($userId) function in the User model or the Log model?
Why not both?
Of course, the main thing is to avoid code duplication as this would be difficult to maintain - and an ugly solution.
The Log Model could contain a method called getActivity() which fetches all activity (or based on any arguments needed for pagination and/or log levels). Additionally, for self-documenting purposes, create a method called getUserActivity($userId) - a method that hopefully looks selfexplainatory.
The User Model could now contain a method called getActivity() (again, with any arguments needed for pagination and/or log levels) which in turn calls the getUserActivity() method in your Log model.
Is this the smartest choice?
Well, there is never a single solution for any problem - but what I like about this solution is that you now have the possibilty to seperate the logic for each of the models, but still have a visible and functional link between them. Secondly, you know have the possibilty to chain User objects to log activity in an easy way.
Since the main used database in your function will be the "Log" one, you should place it in the Log Model.

How would I manage the concept of a User object in PHP?

Okay, I'm still very new to OOP overall, but I've created a few workable classes now and I'm slowly grasping the various concepts of OOP in PHP. On a project that I'm working on currently, a user can register, login/logout, and upload/delete/comment/rate images.
Currently, when a user logs in, I put most of their information (that I have retrieved from a database) inside the $_SESSION superglobal. This includes information such as their first name, username, user_id, etc.
Complementing this, I have a page called user.functions.php which has a number of miscellaneous functions that are related to the concept of a 'user', such as permissions checking, requesting additional user data, checking a successful login, registering a user, etc.
My question is how would I manage this as a User class? If I understand correctly, anything called on a page exists on that page only, so wouldn't I have to declare a
new User();
on each page where I need to perform a task relating to that user? How is that in anyway efficient? Isn't it just simpler to call a function like:
changeAddress();
instead of:
$user = new User();
$user->changeAddress();
What about critical user data such as the user_id, which I currently store in a session? Would I migrate that data inside a class too and retrieve it via a getter method?
Basically, I fail to see how the concept of a user object can improve overall code quality, if a user, which is an inherently cross-page concept, is tied to an object, which exists solely within the confines of a single document?
What am I missing here?
You are dealing with two different different concepts:
Encapusulation of user related functionality in a class.
The stateless nature of the http protocol that causes all information to be lost after a request - response cycle is complete, except for session information that might be preserved between requests through various mechanisms.
As such, the fact that you have to recreate objects or actually any variables will happen no matter what. Creating an object of some class should not cost much. Populating the members is what counts. Following a non-OO methodology would result in populating individual variables instead of members of a class with no gain in performance.
rather than putting all the information individually in the $_SESSION you can store a $user object in session so you can access the user object from any page.
$_SESSION['user'] = new User();
$_SESSION['user']->changeAddress();

Monolithic Model

Background
This is a long and complicated question. I'm using php/MySQL as an example (since it's an actual example) but this could theoretically apply to other languages. Bear with me.
MVC Framework with no ORM
I'm creating an application that uses its own framework. For a variety of reasons, the following answers to this question will not be accepted:
Why don't you just use X framework?
Why don't you just use X ORM?
This application does its own queries (written by me) and that's how I'd like it to stay for now.
Business Logic?
"Business Logic" seems to be a meaningless buzzword, but I take it to essentially mean
The queries and the logic that builds the result set based on those queries
I've also read that the Model in an MVC should do all the business logic.
User.php is 884 lines
Now that I've gotten my app working fairly well, I'd like to refactor it so as not to have such abominations. User.php is essentially the model for Users (obviously). There are some responsibilities I see in it that I could easily pluck out, but a major hurdle I'm running into is:
How can I reconcile SOLID with MVC?
The reason that User.php has grown so large is because I do any query that requires a User member in that file. User is used for a ton of operations (it needs to do so much more than just CRUD), so any query that needs userid, username, etc. is run by a function in this file. Apparently the queries should be in the model (and not the controller), but I feel that this should definitely be split up somehow. I need to accomplish the following:
Create an API that covers all of these necessary queries in a compartmentalized way
Avoid giving access to the DB connection class when it's not necessary
Add User data to the view (User.php is doing that right now -- the view object is injected by a setter, which I think is also bad).
...so what I could do is create other objects like UserBranchManager, UserSiteManager, UserTagManager, etc. and each of those could have the relevant queries and the DB object injected to run those queries, but then how do they get the coveted User::$userid that they need to run these queries? Not only that, but how could I pass Branch::$branchid? Shouldn't those members be private? Adding a getter for them also makes that pointless.
I'm also not sure where to draw the line of how much an object should do. A lot of the operations similar but still different. A class for each one would be huge overkill.
Possible Answer
If I can't get any help, what I'll do (or at least try to do) is have a dependency injection container of some kind build dependencies for the objects above (e.g. UserBranchManager) and inject them into the relevant controller. These would have a DB and Query object. The Query object could be passed to low level models (like User) to bind parameters as needed, and the higher level models or whatever they are called would give the results back to the controller which would add the data to the template as needed as well. Some possible hurdles I see are creating proper contracts (e.g. the UserController should preferably depend on some abstraction of the user models) but some specifics are inevitably required, especially when it comes to the view.
Can anyone offer some wisdom in response to my rambling question?
Response to #tereško
He has provided a great answer not only here, but also at How should a model be structured in MVC?
Code
As requested, here is some extremely pared down code (basically services one request). Some important notes:
Right now, controllers are not classes, just files
The controller also handles a lot of the routing
There are no "view" objects, just the templates
This will probably look really bad
These are also things to improve, but I'm mostly worried about the model (User in particular since it's getting out of control):
#usr.php -- controller
$route = route();
$user = '';
$branch = '<TRUNK>';
if (count($route) > 0) {
if (count($route) > 1) {
list($user, $branch) = $route;
}
else {
list($user) = $route;
}
}
$dec = new Decorator('user');
$dec->css('user');
if (isset($_SESSION['user']) && $_SESSION['user']->is($user)) {
$usr = $_SESSION['user'];
}
else {
$usr = new User(new DB, $user);
}
$usr->setUpTemplate($dec, $branch);
return $dec->execute();
# User.php -- model
class User {
private $userid;
private $username;
private $db;
public function __construct(DB $db, $username = null) {
$this->username = $username;
$this->db = $DB;
}
public function is($user) {
return strtolower($this->username) === strtolower($user);
}
public function setUpTemplate(Decorator $dec, $branch) {
$dec->_title = "$this->username $branch";
// This function runs a moderately complicated query
// joining the branch name and this user id/name
$dec->branch = $this->getBranchDisplay($branch);
}
}
Questions about answers
Answer here:
You talk about leaving off caching/authentication/authorization. Are these important? Why aren't they covered? How do they relate to the model/controller/router?
The Data Mapper example has the Person class with methods like getExemption, isFlaggedForAudit .. what are those? It seems like those calculations would require DB data, so how does it get them? Person Mapper leaves off select. Isn't that important?
What is "domain logic?"
Answer 5863870 (specifically the code example):
Shouldn't these factory objects be abstractions (and not rely on creation via new) or are these special?
How would your API include the necessary definition files?
I've read a lot about how it's best for dependencies to be injected in the constructor (if they're mandatory). I assume you set the factories in this way, but why not the objects/mappers/services themselves? What about abstractions?
Are you worried about code duplication (e.g. most models requiring an _object_factory member in their class definition)? If so, how could you avoid this?
You're using protected. Why?
If you can provide any specific code examples that would be best since it's easier for me to pick stuff up that way.
I understand the theory of what your answers are saying and it's helped a lot. What I'm still interested in (and not totally sure of) is making sure that dependencies of objects in this API are handled in the best way (the worst would be new everywhere).
Dont confuse SOLID (You can get a good explanation of what it is on my blog at: http://crazycoders.net/2012/03/confoo-2012-make-your-project-solid/
SOLID is great when considering the framework that goes around the application you are trying to build. The management of the data itself is another thing. You can't really apply the Single Responsibility of the S of SOLID to a business model that RELIES on other business models such as User, Groups and Permissions.
Thus, you have to let some of the SOLID go when you build an application. What SOLID is good for, is to make sure your framework behind your application is strong.
For example, if you build your own framework and business model, you will probably have a base class MODEL another for DATABASEACCESS, just remember that your MODEL shouldn't be aware of how to get the data, just know that it must get data.
For example:
Good:
- MyApp_Models_User extends MyApp_Framework_Model
- MyApp_Models_Group extends MyApp_Framework_Model
- MyApp_Models_Permission extends MyApp_Framework_Model
- MyApp_Framework_Model
- MyApp_Framework_Provider
- MyApp_Framework_MysqliProvider extends MyApp_Framework_Provider
In this good part, you create a model like this:
$user = new MyApp_Models_User(new MyApp_Framework_MysqliProvider(...));
$user->load(1234);
This way, you will prevent a fail in the single responsibility, your provider is used to load the data from one of the many providers that exist and your model represents the data that you extracted, it doesn't know how to read or write the data, thats the providers job...
Bad way:
- MyApp_Model_User
- MyApp_Model_Group
- MyApp_Model_Permission
define('MyDB', 'localhost');
define('MyUser', 'user');
define('MyPass', 'pass');
$user = new MyApp_Models_User(1234);
Using this bad method you first of all break the single responsibility, your model represents something and also manages the input/ouput of the data. Also, you create a dependency by stating that you need to define constants for the model to connect to the database and you completly abstract the database methods, if you need to change them and have 37 models, you'll have TONS of work to do...
Now, you can, if you want work the bad way... i still do it, i'm aware of it, but sometimes, when you have crappy structure and want to refactor, you can and should work against a principle just to refactor correctly and slowly, THEN, refactor a little more and end up with something SOLID and MVC looking.
Just remember that SOLID doesn't apply to everything, it's just a guideline, but it's very very good guideline.
Well .. it depends on what is actually inside your ./user.php file. If i had to guess, you would be a situation, where your user "model" has too many responsibilities. Basically, you are violating single responsibility principle and not sure how to go about fixing that.
You did no provide any code .. so , lets continue with guessing ...
It is possible that your user "model" is implementing active record pattern. This would be the main source of SRP problems. You could watch this part of lecture slides. It will explain some of it. The point would be, instead of using active record, to go with something similar to a data mapper pattern.
Also, you might notice that some of the domain logic, which works with User class instances, seems to happen outside your "model". It might be beneficial to separate that part in a different structure. Otherwise you will be forcing the domain logic inside the controller. Maybe this comment could shine some light on the whole subject.
Another thing you might have crammed inside your user "model" could be parts of the authorization (no to confuse with authentication) mechanism. It could be pragmatic to separate this responsibility.
Update
You talk about leaving off caching/authentication/authorization. Are these important? Why aren't they covered? How do they relate to the model/controller/router?
Caching is something that you would add later in the application. The domain objects do not care where the data comes from. For that reason you can wither add the caching with in the service-level objects or inside the existing data mappers. I would advise to choose former option, because changing existing mappers might have unforeseen side effects. And because it would just over-complicate the existing mappers.
namespace Application\Service;
class Community{
public function getUserDetails( $uid )
{
$user = $this->domainObjectFactory->build('User');
$cache = $this->cacheFactory->build('User');
$user->setId( $uid );
try
{
$cache->pull( $user );
}
cache( NotFoundException $e)
{
$mapper = $this->mapperFactory->build('User');
$mapper->pull( $user );
$cache->push( $user );
}
return $user->getDetails();
}
}
This would illustrate a very simplified acquisition of user information based on user's ID. The code creates domain object and provides it with ID, then this $user ovject is used as condition to search for cached details or, if it fails, fetching that pulling that information from DB via the data mapper. Also, if that is successful, the details are pushed into the cache, for next time.
You might notice, that this example did not handle situation, when mapper cannot find such user with such ID in storage (usually - SQL database). As I said , it's a simplified example.
Also, you might notice, that this sort of caching can be easily added on case-by-case basis and would not drastically change how your logic behaves.
Authorization is another part, which should not directly influence your business logic. I already linked my preferred way for providing authentication. The idea is that, instead of checking for credentials inside controller (like here, here, here or here), the access rights are checked before you execute a method on the controller. This way you have additional options for handling the denial of access, without being stuck within a specific controller.
The Data Mapper example has the Person class with methods like getExemption(), isFlaggedForAudit() .. what are those? It seems like those calculations would require DB data, so how does it get them? Person Mapper leaves off select. Isn't that important?
The Person class is a domain object. It would contain the part of domain logic, that is associated directly with that entity.
For those methods to be executed, the mapper should at first load the data. In PHP it would look something like this:
$person = new Person;
$mapper = new PersonMapper( $databaseConnection );
$person->setId( $id );
$mapper->fetch( $person );
if ( $person->isFlaggedForAudit() )
{
return $person->getTaxableEearnings();
}
The names of methods in the PersonMapper are there as an example, so that you would understand, how the class is supposed to be used. I usually name methods fetch(), store() and remove() (or push/pull/remove ... depends on how much GIT have I been using). IMHO, there is no point to have a separate update() and insert() methods. If object's data was initially retrieved by mapper, then it is an UPDATE. If not - it is an INSERT. You can also determine it whether the value, which corresponds to PRIMARY KEY has been set or not (in some cases, at least).
What is "domain logic?"
It is part of the code which knows how to create an invoice and apply discount price for specific products. It's also the code which makes sure, that you do not submit registration form, you do not state that you have been born in 1592.
The MVC is made from two layers: presentation (can contain: views, templates, controllers) and model layer (can contain: services, domain objects, mappers). The presentation layer deals with user interaction and responses. The model layer deals with business and validation rules. You could say that domain business logic is everything in model, that does not deal with storage.
I guess there is no easy way to explain.
Shouldn't these factory objects be abstractions (and not rely on creation via new) or are these special?
Which "factory objects", where? Are you talking about this fragment ?
$serviceFactory = new ServiceFactory(
new DataMapperFactory( $dbhProvider ),
new DomainObjectFactory
);
$serviceFactory->setDefaultNamespace('Application\\Service');
That whole code fragment is supposed to be in bootstrap.php file (or you might be using index.php or init.php for that). It's the entry point for the application. It is not part of any class, therefore you cannot have *tight coupling" there. There is nothing to "couple with".
How would your API include the necessary definition files?
That fragment is not entire bootstrap.php file. Above that code are includes and initialization for autoloader. I am currently using dynamic loader, which lets classes from same namespace to be located in different folders.
Also, such autoloader is a development-stage artifact. In production code you have to use loader, which works with predefined hashtable and does not need to actually walk the tree of namespaces and locations.
I've read a lot about how it's best for dependencies to be injected in the constructor (if they're mandatory). I assume you set the factories in this way, but why not the objects/mappers/services themselves? What about abstractions?
What are you talking about ?!?
Are you worried about code duplication (e.g. most models requiring an _object_factory member in their class definition)? If so, how could you avoid this?
Did you actually LOOK at how old that code fragment in comments was ?!?!?
You're using protected. Why?
Because, if values/methods are defined with protected visibility, you can access them when you extend the original class. Also, that code example was made for old version of answer. Check the dates.
And no. I will not provide any specific code examples. Because each situation is different. If you want to do copy-paste development, then use CakePHP or CodeIgniter.

OOP Structure for a PHP/Twitter/Facebook App

I'm making a simple PHP application with Twitter/Facebook integration to practice OOP concepts and patterns, and I need help with how it should be designed.
What my app will do
Basically, once the user logs in, he's show a form with title and body field. When he clicks on "Post", this content will be appropriately transformed and posted to Facebook and Twitter. Of course, he'll also get an option to authenticate my FB/Twitter app if he hasn't already done so. That's what I'm trying to achieve.
The structure I've come up with till now
Since database access will have to be shared amongst multiple files, I'm using a Singleton pattern. Essentially, I have a DB class with a static mysqli link and a static method to get this database link. The models will use mysqli functions with this single link. (I don't want to abstract the database type just yet.)
I have a User class which holds a user's data, like it's id, username and hashed password. It has methods to retrieve user based on id, credentials and even save the current user to the db.
An Auth class manages session and returns a User object for a valid user. So, it manages logging in, and keeping the user logged in between page visits.
The structure I'm having problem with
I now need access to the Twitter and Facebook information of the user. Of course, they'll be in separate tables, and have separate classes to interact with them. But each of this class is associated with a User.
So, when I'm fetching user information from the database, I'll also use JOINs to fetch corresponding data from the Twitter and Facebook table. Then, my plan is to have a Twitter and Facebook object instantiated within my User object. So, these two classes can be accessed as say $user->twitter->post("Something");.
Is this a good structure, or is there a better way to organize classes? This is a simple app, and coding is not my concern. My concern is the structure, since I should be able to add new social networks to the application.
It is preferable to keep persistence functions out of domain objects. Instead of having the User class load and save itself, I would have a UserRepository interface, for example:
interface UserRepository {
public function findUser($username);
public function save(User $user);
}
and a MysqlUserRepository class that implements this interface. That way you keep database-specific code out of the User class.
Similarly, I would pull social networking functions into their own interface, say:
interface SocialNetworkService {
public function post($status);
}
and separate implementations for FacebookService and TwitterService. This allows you to add support for new social networks without having to modify the User class.
These services can then simply wrap around a user object and provide their services for that user:
$fb = new FacebookService($user);
$fb->post("blah");
A common principle behind all of these decisions is the single responsibility principle: your User class should have only one reason to change, and that is when you need to change the model of a user. Any other changes, such as dealing with databases or social networks, shouldn't affect the User class.

PHP confusion while building a script

I am facing some confusion because i have decided to convert from procedural to oop, I Find it more efficient.
So anyway I've got some questions i hope i find answers here :)
Let's say am working on a php Registeration System which requires
1-Signup process
2-Activation Process
3-Login process (which requires)
Validating inputs
Validating Sessions, etc
The questions is: Should i make class for every process Or i can combine all of them into one class named 'User', with methods to login, signup, activate and so on, Or can i make 1 class named USER which has user's properties, and signup, login classes extends it ?
Should i use separated classes for Sessions, Validating etc ? or just normal Checking inside the main class
Should i Separate ADMIN classes from normal classes ? meaning I have a USER class, which has methods, to login user, signup user etc, should i add more functions for admin like DELETE user, UPDATE user ? or separate it from the normal classes
You should make a User class with different functions for login signup and whatever.
You should separate different functions into as many classes/objects as you feel suits. For instance, with your User class you might have a Session class which you use within your User class to do the session management stuff. You could also create a Person class which User inherits from. This can have functions like printFullName and such, whereas the User class has auth specific stuff like login and register.
Again, its up to you. You can do whatever you want. I would probably have a UserAdmin class which has functions like deleteUser($userid) and editUser($userid) just because then its not confusing it with the auth side of things. However it can be done the other way. You could call a User object for a specific user and call deleteUser() on that to delete the user. Its what you feel most comfortable with.
As with all my answers, its what you want to do. There is no standard to this, and no rules. OOP is mainly about layering everything so that it makes sense, structurally, and about creating reusable code.
Another thing you want to look at is MVC programming. MVC stands for Model, View, Controller. In this set up you actually differentiate objects not by category (e.g. user, page etc) but by their function (e.g. model - connects to a database, view - has the code to layout a page, controller - computes stuff and passes data to the view). If you look at something like codeigniter then this will become more apparent to you.
Now you can create a model for users. In this model you can do all the database stuff, adding, editing, deleting users and such. This can then interface with a controller which will layout the page, e.g. seeing if the user is currently logged in, calling the user's model and getting the name of the user from the model, then passing it to the view to display on screen. This will make much more sense when you start using frameworks like code igniter.
Anyway, good luck in your learning.
It's really your own choice what is in a class and what is not. Mostly it's about what you find to create a good overview and what makes certain use-cases easier. In this case it will most likely cause more confusion if you split these operations, instead of putting them under the same banner.
I'd under most circumstances choose to put validation, signup, etc. in the same class. If admins are also users (and not a whole new table of users for example) I'd also include these in the same class - Or maybe create an admin class that extends the user class.
But there's no ultimate law of what is put in one class and what is not. It's about trial and error and seeing what gives you a good overview, and when you come to building abstraction layers, extending classes, etc. you need to be a little more careful. Taking the right steps can save you a ton of work in later work with extending classes.
I made the switch about 6 months ago from functional to OOP. I read a shitload of papers trying to figure out what the big deal about OOP is.
I think a conceptual understanding is important in this case. Think of an object as a physical thing.
A car:
A car has properties:
color
remaining petrol
top speed
A car has methods:
start
stop
accelerate.
1) A user is an object, login, logout, signup are actions/methods that a user does.
2) A user has session variables(properties) so I would place them as properties in the class
3) An admin user has more methods, but still needs acess to old ones. So idealy an admin user should inherit the properties and methods, I think this is done with the Extends keyword. This is called subclassing, or inhertance.
You best is to google "understanding oop concepts" and read whatever connects with you

Categories