How to check an object class within an other object - php

I’m just learning OOP Php, I understand the basic principles of OOP programming, and trying to do exercises. I wanna do a simple messaging application, where users can message each other. Like email, but in a closed system.
My idea is when an user logs in, i create an user object that contains the function that an user can do and if an admin logs in i create an admin object that extends the user class with added admin functions.
My question is Can I check in other class if the object is an admin or an user class without injecting in the classes or create the objects inside the checking class. Like this:
class Checker{
// some variables
public function isAdmin($object ){
if($object istanceof Admin){
return 1;
} else{
return 0;
}
}
}

IMO using reflection and introspection for non-debug purposes is an anti-practice.
PHP 5 Reflection API performance
Do it like this:
class User implements SystemUserInterface
{
public function isAdmin()
{
return false;
}
}
class Admin extends User
{
public function isAdmin()
{
return true;
}
// other stuff that only admin can do..
}
function checkUser($user)
{
echo "You have created ".($user->isAdmin()? "admin":"regular")." user";
}

Related

Trying to abstract the Database class and stop it's public usage : Laravel 5.2.31

I have following classes
Interface
interface IRole {
public function All();
}
In below class, I will also write some logic before sending the data to Database layer and some code after data is retrieved from Database class
class RoleBL implements IRole {
public function All() {
return (new RoleDb())->All();
}
}
Database class
class RoleDb {
public function All() {
$Roles = \App\Models\Role\RoleModel
::all();
return $Roles;
}
}
Below is my Controller Action Method
class MembershipController extends \App\Http\Controllers\BaseController
{
private $role;
public function __construct(IRole $_role) {
$this->role = $_role;
parent::__construct();
}
public function create() {
$RoleTypes = $this->role->All();
return view('Membership.Create', array('Roles' => $RoleTypes));
}
}
Can somebody help me how can I stop direct access to RoleDb class? It's access modifier is public right now.
You should not even try to do that. At PHP it will look more like hacks. Just keep one code style and if you work in team then write some guidelines.
Keep all your objects in separate layers based on their purpose. Database related objects in data access layer. Domain objects in domain layer.
Models at domain layer represent all business objects that business talk about (role, customer, comment, payment, etc.) and all related actions on them (user->register, user->assignRole, blog->postArticle, etc.). These models hold business requirements, rules.
Models at data access layer represents all objects that persists state of those business objects and finds them in specific ways (blog->getUnreadPosts, user->findAdministrators, etc.).
If by RoleBL you mean role business logic then it should be part of domain (your business requirements). These objects are persisted/retrieved by DAL.
Your business objects should not know anything about data access layer. (new RoleDb())->All(); means reading from database. To fix this you can create separate read model at DAL for querying your business objects. That means there will be separate model (e.g. RoleDataModel) at DAL for designing query side based on business/application needs.
namespace Domain
{
class Role
{
private $id;
private $title;
/* etc. */
public function getId()
{
return $this->id;
}
}
class Person
{
private $roles = [];
/* etc. */
public function assignRole(Role $role)
{
// person already promoted?
// can person be promoted ?
// if you promote person then it might not be required to add instance af this $role
// to $this->roles array, just add identifier from this role
// If you would like to respond on what did just happen
// at this point you can return events that describe just that
}
public function getRoles()
{
return $this->roles;
}
}
}
namespace DAL
{
class Person
{
function storePerson(Person $person)
{
// here you can use eloqueent for database actions
}
function getAllAdministrators()
{
}
}
}
There will be separate Person class for eloquent. Use that just for data manipulation. Map data from eloquent objets to Data Transfet Objects or your Business Layer Objects. DTOs can be more specific to your other layers like UI where you might not need to show everything that BLOs contains. DTOs for your UI will model everything your UI needs.
Get familiar with some of the DDD and overall programming concepts. I should be able to look up something that will fit your needs.

Singleton Class in Laravel 5

I'm using Laravel Framework version 5.2.32. I wish to create a Singleton class whose object is accessible accross all controllers. I've implemented the class as below.
class SingletonClazz {
private static $instance;
protected function __construct() {
//Do nothing
}
public static function getInstance() {
if (empty(SingletonClazz::$instance)) {
SingletonClazz::$instance = new SingletonClazz();
echo 'Created';
}
else {
echo ', Already created';
}
return SingletonClazz::$instance;
}
}
I'm creating an object of the class as below
class MyController extends Controller {
public function initSingleton() {
SingletonClazz::getInstance();
SingletonClazz::getInstance();
SingletonClazz::getInstance();
}
}
The route.php file is configured as below
Route::group(['prefix' => 'singleton'], function() {
Route::get('/', [
'uses' => 'MyController#initSingleton'
]);
});
When I invoke the URL http://localhost:8080/singleton/initSingleton the result is 'Created, Already created, Already created'. When I invoke the URL again, the result is the same whereas I expect it to be 'Already created, Already created, Already created'
Can you guide on the problems with this implementation.
With each request send to the PHP server, it is handled as a blank sheet so it is initializing Lavarel from the beginning. Variables defined in the previous request are not automatically saved to the next one.
It is how PHP is designed, build on top of the HTTP protocol that is also designed this way.
What you can do is store the object in a session:
<?php
session_start();
if(isset($_SESSION['instance'])){
$singleton = $_SESSION['instance'];
} else {
$singleton = SingletonClazz::getInstance();
$_SESSION['instance'] = SingletonClazz::$instance;
}
?>
But then again why would you want that and if so, I really suggest changing your implementation.
A singleton is structure code, where you have multiple classes with a similar interface, useless data should not be stored into sessions.
Why you didn't use Laravel IoC for implementing singleton?
Jeff Lambert in comments are totally right.

Storing a model instance as a service during the session

I want to access to profile of the current user across the application (read/write). The user profile is an in instance of User model. Is it possible to store it on session as a service? If not, what is best practice?
Here is my login code. (ajax-based login)
function loginAction()
{
$this->view->disable();
{
$request = (array)$this->request->getJsonRawBody();
$user = User::findFirstByUsername($request['username']);
if (password_verify($request['password'], $user->password)) {
$userModel = User::findFirst('username="'.$request['username'].'"');
$this->getDI()['session']->set('auth', $user->id);
$this->user = $user;
jsonResponse($user);
} else {
http_response_code(401);
jsonResponse(['message' => 'invalid']);
}
}
}
There is several ways to achieve that. Let me share with you the one I've used in my own project...
First I've created a Component to deal with authentication related stuff such as checking the current session status (guest, user, admin), storing the current user specs, authentication procedures, etc.
namespace MyApp\Components;
use Phalcon\Mvc\User\Component as PhComponent;
class Authentication extends PhComponent
{
// ...
}
Then, I've registered this component in the main App's DI container:
$di->setShared('authentication', 'MyApp\Components\Authentication');
So I can use from my controllers, views, etc. Like:
function homeAction()
{
//...
if($this->authentication->isGuest()) {
//...
}
Finally to store data using the session. Phalcon provide a persistent session bag that you can use to easily store a serialized version of the model in the current session:
class Authentication extends PhComponent
{
// ...
function authenticate($username, $password)
{
// ... Authentication logic
if($validCredentials) {
$this->persistent->currentUser = $userModel;
}
// ...
}
}

CakePHP share controller view/functions

I don't know how to do this:
I have a CakePHP project that uses AdministratorsController and UsersController for different roles, etc.. but, a User can save a Message and a Administrator too! So, should I repeat the same function or what?
function saveMessage(){
$this->autoRender = false;
if (!$this->RequestHandler->isPost())
$this->Session->setFlash('Error 78.', 'flash_custom_danger');
else{
if(!$this->Message->save($this->request->data))
$this->Session->setFlash('Error 985.', 'flash_custom_success');
else
$this->Session->setFlash('Success!', 'flash_custom_success');
}
$this->redirect('/');
}
Move the function to app_controller, because both your controllers will extend from it.
In the app_controller:
function my_function($controller_specific_string = null){
//stuff here common to both controllers
}
In the controller(s):
function my_function() { //extended function in both controllers
// do controller specific stuff here...
return parent::my_function('from_users_controller');
}
Ok, just for this kind of case (normally I'd advice to put the functionality in the model or in AppController) I'd just create a parent class.
Let's call it GeneralUsers (to late for imagination)
class GeneralUsersController extends AppController {
protected function _saveMessage(){
$this->autoRender = false;
if (!$this->RequestHandler->isPost())
$this->Session->setFlash('Error 78.', 'flash_custom_danger');
else{
if(!$this->Message->save($this->request->data))
$this->Session->setFlash('Error 985.', 'flash_custom_success');
else
$this->Session->setFlash('Success!', 'flash_custom_success');
}
$this->redirect('/');
}
}
And let's have your UsersController and AdministratorsController extend from that one
class UsersController extends GeneralUsersController {
public function myAction() {
$this->_saveMessage();
}
}
// and the Administrator controller one
That way the only controllers with those functions are users and administrators.
Now, if this was the case where a bunch of validations are made before saving and you want to avoid repeating those, I'd say to put that in the models. If every controller should have access to that function, then put it in the AppController. But since an "Administrator" is an "User" with more privileges (and you are not separating that functionality with the "admin_" prefix), then go with an extra parent class. Be careful with the functions though, don't let them be public unless you want those to be accessible by url.

codeigniter instance of model class

I'm developing a site with codeigniter. Now, normally when you use a class in codeigniter, you basically use it as if it were a static class. For example, if I head a model called 'user', I would first load it using
$this->load->model('user');
and than, I could invoke methods on that user class like
$this->user->make_sandwitch('cheese');
in the application that I'm building, I would like to have one UserManagement class, which uses a class called 'user'.
so that, for example I could
$this->usermanager->by_id(3);
and this would return an instance of the user model where the id is 3.
What's the best way to do that?
The model classes in CI are not quite the same thing as model classes in other syntax's. In most cases, models will actually be some form of plain object with a database layer which interacts with it. With CI, on the other hand, Model represents the database layer interface which returns generic objects (they're kinda like arrays in some ways). I know, I feel lied to too.
So, if you want to make your Model return something which is not a stdClass, you need to wrap the database call.
So, here's what I would do:
Create a user_model_helper which has your model class:
class User_model {
private $id;
public function __construct( stdClass $val )
{
$this->id = $val->id;
/* ... */
/*
The stdClass provided by CI will have one property per db column.
So, if you have the columns id, first_name, last_name the value the
db will return will have a first_name, last_name, and id properties.
Here is where you would do something with those.
*/
}
}
In usermanager.php:
class Usermanager extends CI_Model {
public function __construct()
{
/* whatever you had before; */
$CI =& get_instance(); // use get_instance, it is less prone to failure
// in this context.
$CI->load->helper("user_model_helper");
}
public function by_id( $id )
{
$q = $this->db->from('users')->where('id', $id)->limit(1)->get();
return new User_model( $q->result() );
}
}
Use abstract factory pattern or even Data access object pattern which does the job that you require.
class User extend CI_Model
{
function by_id($id) {
$this->db->select('*')->from('users')->where('id', $id)->limit(1);
// Your additional code goes here
// ...
return $user_data;
}
}
class Home extend CI_Controller
{
function index()
{
$this->load->model('user');
$data = $this->user->by_id($id);
}
}

Categories