Abstract class to handle permission-based functions - php

I've built an abstract User class which is extended by Admin, Manager, and Employee. User contains everything that all Users will need, and abstracts everything that each user handles using different logic based on the instance. My confusion comes in when I have functionality that an Admin or Manager class will handle the exact same way, but an Employee won't be able to access at all.
For example, managing a user other than itself should be restricted to only Admins and Managers while an Employee should never be able to do this. I want to avoid copy/pasting the exact same logic in both the Admin and Manager class, so should I make a single private function and move it up to the User class and simply have the Admin/Manager classes call it from there?
abstract class User
{
public $username;
public $userId;
public $company;
public $error;
private function updateUser($user)
{
// Logic for saving the user info
}
....
}
class Admin extends User
{
public function updateUser($user)
{
parent::updateUser($user)
}
....
}
class Manager extends User
{
public function updateUser($user)
{
parent::updateUser($user)
}
....
}
class Employee extends User
{
public function updateUser($user)
{
$this->error = "Invalid Permissions";
}
....
}
Should this be handled differently? Thanks.

You could move the logic into the User base class with a check to ensure that the specified user is either a manager or admin, but you could add different 'classes' of users at a later date which may need the same functionality, in which case the code you wrote will need to be updated.
My suggestion would be a new abstract class that sits in between the Manager/Admin users and the User abstract class, maybe something like UserEditor. UserEditor extends User and provides the functionality for Admin/Managers to update other users, and Admin/Managers extend from UserEditor instead of your User class.

If you do it like this i think that you should have an ACL class and performa a check in the function so that you don't need to override anything
abstract class User
{
public $username;
public $userId;
public $company;
public $error;
private final function updateUser($user)
{
if(ACL::checkIfUserHasPermissionToUpdateUser($this->userId){
//Perform the update, this code will be executed only if the user
//is a Manager or an Admin, but the logic is delegated to the ACL class
}
}
}

Related

Yii2 basic template to make separate session for frontend & backend

I am using the Yii2 basic template to create an admin panel.
For the admin login I have used the useridentity class and the default user model of yii.
Now I have to create the login for the frontend. What should I do to make the separate login so that I can login in the same browser in frontend and backend?
In basic template I'm facing problem with same identity class and model.
I have to use the same user table of database for admin and frontend user.
Please suggest the best way to manage this.
This is actually the correct way to do it and to work around this "Problem" is to declare different sessions for your frontend and backend.
Yii2 advanced template has this feature included in the stock and I would suggest you not to start inventing the wheel again and just move your project to the advanced template.
Ofcourse you can create a new model and a new table for just the admins. However this new class should still implement IdentityInterface
Something where your AdminUserModel looks something like this:
namespace app\models;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface
class AdminUser extends ActiveRecord implements IdentityInterface
{
/** Dont froget all the related stuff like behaviours, properties etc **/
/**
* #inheritdoc
*/
public static function tableName()
{
return 'admin_user';
}
public static function findIdentity($id)
{
return static::findOne($id);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
public function getId()
{
return $this->id;
}
public function getAuthKey()
{
return $this->authKey;
}
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
}
And if you decide to go this route, I would even suggest you to extend regular User model in AdminUser model, since a lot of the properties and functionality will be the same.
I suggest use module to create an admin panel.

PHP OOP UML Separate databse config details from class

I am developing a eCommerce store for school project.
i have several classes like this that uses same database connection.
so i have to separate those.
1. how to use a single database connection file for all of my classes.I have sevaral classes same as this
2. I draw some use case and class diagram. if any one has experience in UML - (ecommerce ) can you verify those?
class abc {
public $id;
public $name;
public $email;
public $db;
function __construct()
{$this->db=new mysqli('localhost','root','','cart');}
public function newsletter_subcribe()
{$sql="insert into table (id,name,email) value('$this->id','$this->name','$this->email')";
$this->db->query($sql);}
this class is do some query to your database for CRUD, the best thing you can do is make one more controller to access to this class, also make sure every function to do that is in private, not public.
so basicly the controller will post data to class to do CRUD.
more like Model in CI.
CONTROLLER -->> YOUR CLASSS -->> DATABASE
CLASS A
{
private function dbconnection()
{
}
private function a($param)
{
dbconnection();
//CRUD HERE
}
}
CLASS B
main function()
{
//load class A here, and you can access all method
$result = a($param);
}

Getting user data

There are two parts to this application I've been building. There's the website which is powered by the CMS and there's the CMS (wrestling manager) that goes with it. With the two controllers I created called frontend and backend I use those accordingly. The frontend controller is responsible for the code that needs to be ran across all controllers on the website. The backend controller is responsible for the code that needs to be ran across all controllers on the CMS.
I'm looking for the ideal way to work with the user data after the user successfully logs in again gets directed to the dashboard which is extended by the backend controller. I've heard different solutions for example a hook. That's just one I've heard.
Inheritance is your friend here
You would simply create a master controller(front-controller) that extends CI_Controller
You might consider doing a SPA application, if so there are many great frameworks to help you achieve this, quite a popular one is angular.js
some more useful reading on the subject...
class MY_Controller extends CI_Controller
{
protected $currentUser;
protected $template;
public function __construct()
{
//You talked about hooks
//this constructor is the same as saying
//post_controller_constructor
$this->template = 'master/default';
}
//Ok so what functions need to be run
//throughout the application
//run them once here, keeping our app DRY
protected function isAjax()
{
return ($this->input->is_ajax_request())
? true
: show_error('Invalid Request!');
}
protected function isLoggedIN()
{
//load your auth library maybe here
$this->load->library('auth');
//check you have a "current logged In user"
//expect object or null/false
$this->currentUser = $this->auth->getLoggedInUser();
return ($this->currentUser) ?: false;
}
}
class Frontend_Controller extends MY_Controller
{
public function __construct()
{
parent::__construct();
}
public function testFirst()
{
//maybe you just need to test for ajax request here
//inheritance from parent
$this->isAjax();
}
public function testSecond()
{
//maybe you DO need a user logged in here
//inheritance from parent
$this->isAjax();
//or yet again, abstract this to the parent level
if(!$this->currentUser || is_null($this->currentUser))
{
//handle errors on frontend
return $this->output->set_status_header(401); //un-authorized
}
}
}

How to generate database table models with Gii in Yii?

Problem:
I used gii to generate database table models. So If I have any change in users table structure, I used gii and all my relations and other methods are removed from class. So I need to make backup of class and regenerate class and bring back other methods and relations.
Possible Solution:
I changed my class into two classes like this for a table 'users':
class Users extends UsersMapper {
public function tableName() {
return 'users';
}
public function rules() {
.....
}
public function relations() {
.....
}
}
class UsersMapper extends CActiveRecord {
public function getAllUsers() {
......
}
public function getBlockedUsers() {
......
}
}
Question:
Above method is working for me and I am using only Users class everywhere in my code. Is it valid method or there is any problem with this logic. Is there any other method.
Thanks
The Giix extension will create a models/Users class and a models/_base/BaseUsers class for your case. The Users class extends the BaseUsers class. Thus only the BaseUsers class needs to be regenerated on changing the database. It also comes with a couple of extra methods that I use quite a lot.

instantiate different class based on the object type in PHP

I am searching for a architectural solution in instantiating different child classes based on an object type or extending Base class with the methods of child classes.
To give an example:
There is a base class User and several child classes Partner, Client, Moderator which have specific methods an their own constructors.
When I am calling
$user = new User($userid);
I want User class
class User
{
public function __construct($userid) {
self::initDB();
if ($this->isPartner()) {
//extend this class with the methods of "Partner" child class and run "Partner" class constructor
}
if ($this->isClient()) {
//extend this class with the methods of "Client" child class and run "Client" class constructor
}
if ($this->isModerator()) {
//extend this class with the methods of "Moderator" child class and run "Moderator" class constructor
}
}
}
To return me an object with all of the methods depending on what roles does user have.
I know my logic is broken somewhere and the example I provided is wrong. But the only solution I see now is to build one giant class that has all of the methods for all of the roles - which looks like a mess.
First of all, your database logic should be totally separate from your domain objects (User, etc). Otherwise you are violating the single responsibility principle (SRP).
Set up your classes something like the following (base class User and multiple subclasses):
class User
{
private $id;
// getters and setters go here
}
class Moderator extends User {}
class Partner extends User {}
// etc
Then, create some sort of UserManager class that implements an interface that looks like the following:
interface UserManagerInterface {
function loadUserById($id);
}
The implementation of that method should load the passed user id's information from the database, look at what type it is (partner, moderator, etc) and then instantiate the appropriate class and hydrate the appropriate information.
The problem is that you cannot call new User and get anything other than a User object.
This sounds like the perfect use-case for the factory pattern.
The simplest form of this uses a static method to invoke the correct constructor.
So you could have code like this:
class User {
public static function create($userid) {
// get user from the database
// set $isPartner to true or false
// set $isClient to true or false
// set $isModerator to true or false
if ($isPartner) {
return new Partner($userid);
} elseif ($isClient) {
return new Client($userid);
} elseif ($isModerator) {
return new Moderator($userid);
} else {
return new User($userid);
}
}
}
You can then call User::create($userid) to get the appropriate object.
If your code is appropriately structured, it may well be possible to have code along the lines of Lusitanian's answer (fleshed out) that would do a better, more flexible job.

Categories