Yii2 basic template to make separate session for frontend & backend - php

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.

Related

How to make a REST API first web application in Laravel

I want to make an API first application in Laravel. I don't know what is the best approach to do this, I will explain what I am trying to do, but please feel free to give answers how to do this in a different way.
I don't want all my frontend to be written in javascript and parse the JSON output of the API with angular.js or something similar. I want my Laravel application to produce the HTML views. I am trying to go down the road of having two controllers one on for the API and one for the web. For the show User action my routes.php looks like this:
# the web controller
Route::controller('user', 'WebUserController');
# the api controller
Route::group(array('prefix' => 'api'), function() {
Route::resource('user', 'UserController');
});
So /user will take me to WebUserController and /api/user will take me to the UserController. Now I want to put all my logic in the API UserController, and call its actions from the WebUserController. Here is the code for both of them:
class UserController extends BaseController
{
public function show($id)
{
$user = User::find($id);
return Response::json(array('success'=>true,'user'=>$user->toArray()));
}
}
class WebUserController extends UserController
{
public function getView($id)
{
# call the show method of the API's User Controller
$response = $this->show($id);
return View::make('user.view')->with('data', $response->getData());
}
}
In the WebUserController I am able to get the json content of the response with getData(), but I am not able to get the headers and status code (they are protected properties of Illuminate\Http\JsonResponse).
I think that my approach might not be the best, so I am open to suggestions how to make this app.
EDIT: The question how to get the headers and status of the response has been answered by Drew Lewis, but I still think that there might be a better way how to design this
You should utilize the Repository / Gateway design pattern: please see the answers here.
For example, when dealing with the User model, first create a User Repository. The only responsibility of the user repository is to communicate with the database (performing CRUD operations). This User Repository extends a common base repository and implements an interface containing all methods you require:
class EloquentUserRepository extends BaseRepository implements UserRepository
{
public function __construct(User $user) {
$this->user = $user;
}
public function all() {
return $this->user->all();
}
public function get($id){}
public function create(array $data){}
public function update(array $data){}
public function delete($id){}
// Any other methods you need go here (getRecent, deleteWhere, etc)
}
Then, create a service provider, which binds your user repository interface to your eloquent user repository. Whenever you require the user repository (by resolving it through the IoC container or injecting the dependency in the constructor), Laravel automatically gives you an instance of the Eloquent user repository you just created. This is so that, if you change ORMs to something other than eloquent, you can simply change this service provider and no other changes to your codebase are required:
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind(
'lib\Repositories\UserRepository', // Assuming you used these
'lib\Repositories\EloquentUserRepository' // namespaces
);
}
}
Next, create a User Gateway, who's purpose is to talk to any number of repositories and perform any business logic of your application:
use lib\Repositories\UserRepository;
class UserGateway {
protected $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function createUser(array $input)
{
// perform any sort of validation first
return $this->userRepository->create($input);
}
}
Finally, create your User web controller. This controller talks to your User Gateway:
class UserController extends BaseController
{
public function __construct(UserGatway $userGateway)
{
$this->userGateway = $userGateway;
}
public function create()
{
$user = $this->userGateway->createUser(Input::all());
}
}
By structuring the design of your application in this way, you get several benefits: you achieve a very clear separation of concerns, since your application will be adhering to the Single Responsibility Principle (by separating your business logic from your database logic) . This enables you to perform unit and integration testing in a much easier manner, makes your controllers as slim as possible, as well as allowing you to easily swap out Eloquent for any other database if you desire in the future.
For example, if changing from Eloquent to Mongo, the only things you need to change are the service provider binding as well as creating a MongoUserRepository which implements the UserRepository interface. This is because the repository is the only thing talking to your database - it has no knowledge of anything else. Therefore, the new MongoUserRepository might look something like:
class MongoUserRepository extends BaseRepository implements UserRepository
{
public function __construct(MongoUser $user) {
$this->user = $user;
}
public function all() {
// Retrieve all users from the mongo db
}
...
}
And the service provider will now bind the UserRepository interface to the new MongoUserRepository:
$this->app->bind(
'lib\Repositories\UserRepository',
'lib\Repositories\MongoUserRepository'
);
Throughout all your gateways you have been referencing the UserRepository, so by making this change you're essentially telling Laravel to use the new MongoUserRepository instead of the older Eloquent one. No other changes are required.
You should be use Repository for this design.
Example -
//UserRepository Class
class UserRepository {
public function getById($id)
{
return User::find($id);
}
}
// WebUser Controller
class WebUserController extends BaseController {
protected $user;
public function __construct(UserRepository $user)
{
$this->user = $user;
}
public function show($id)
{
return View::make('user.view')->with('data', $this->user->getById($id));
}
}
// APIUser Controller
class UserController extends BaseController {
protected $user;
public function __construct(UserRepository $user)
{
$this->user = $user;
}
public function show($id)
{
$data =>$this->user->getById($id);
return Response::json(array('success'=>true,'user'= $data->toArray()));
}
}
Checkout Laravel's RESTful controllers:
http://laravel.com/docs/controllers#restful-controllers
Their docs do a pretty good job.
But even better is this tutorial:
http://code.tutsplus.com/tutorials/laravel-4-a-start-at-a-restful-api-updated--net-29785
This is a video by Jeffrey Way he is one of the better Laravel developers. In this tutorial he is connecting a BackboneJS application to a RESTful service that he sets up in Laravel. It doesn't get any better then this. I can write you a lot of boilerplate, but just learn it by watching a nice video and having a coffee. ;)
https://www.youtube.com/watch?v=uykzCfu1RiQ
I have a response to the problem you are having with the Response.
You can get the headers, status code and data from the Response.
// your data
$response->getData();
// the status code of the Response
$response->getStatusCode();
// array of headers
$response->headers->all();
// array of headers with preserved case
$response->headers->allPreserveCase();
$response->headers is a Symfony\Component\HttpFoundation\ResponseHeaderBag which inherits from Symfony\Component\HttpFoundation\HeaderBag
I would also recommend using a repository.
Attempting to call one controller from another would be falling into a pattern called HMVC (Hierarchical model–view–controller).
This means that your entire application relies on lower modules.
In this case, your API would serve as a repository for your data (which isn't the worst thing in the world at first).
However, when you then modify the structure of how data is returned in your API, everything else relying on it would have to know how to respond.
Say you wanted to have authorization checks to see if a logged in user should be able to see the details of a returned user and there was an error.
In the API, you would return a Response object with a 403 forbidden code and some meta data.
Your HTML controller would have to know how to handle this.
Contrast this to a repository which could throw an exception.
public function findById ($id)
{
$user = User::findOrFail($id);
if (Auth::user->hasAccessTo($user)) {
return $user;
} else {
throw new UnauthorizedAccessException('you do not have sufficient access to this resource');
}
}
And your API controller would look more like this:
public function show($id)
{
try {
return $this->user->findById($id);
} catch (UnauthorizedAccessException $e) {
$message = $e->getMessage();
return Response::json('403', ['meta' => ['message' => $message]]));
}
}
Your HTML controller would then look like this:
public function show($id)
{
try {
$user = $this->user->findById($id);
} catch (UnauthorizedAccessException $e) {
Session::flash('error', $e->getMessage());
// Redirect wherever you would like
return Response::redirect('/');
}
}
This gives you very reusable code and let's you change your controller implementations independently without worry of changing the other's behavior.
I wrote more on how to implement the repository pattern in this post: you can ignore the interface and skip right to the implementations if you would like.

What are the practices for working from a "Fat model, skinny controller" perspective with Laravel Eloquent ORM? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been picking other developers' brains on the concept of "fat models, skinny controllers" after reading:
http://culttt.com/2013/07/01/setting-up-your-first-laravel-4-controller/
http://culttt.com/2013/05/13/setting-up-your-first-laravel-4-model/
Most respondents are using what I'd consider fat controllers.
While the topic has come up on Stack Overflow I haven't found thorough description of the method in practice.
I just found an old related question here.
Skinny Controllers
What you are going to see in PHP (vanilla or Laravel or Symfony) more and more are the skinniest controllers ever. This is something you already see in Rails, and people are also starting to call it (with some other practices) hexagonal. One line of code is all you need in your controller, actually they say this should be a goal for all your methods. This is an example with, yes, a little bit more than that, but still skinny:
<?php
class PostController extends Controller {
private $repository;
public function __construct(PostRepositoryInterface $repository)
{
$this->repository = $repository;
}
public function store()
{
try
{
$this->repository->create(Input::all());
}
catch (ValidationException $e)
{
return Redirect::back()->withInput()->withErrors($e->all());
}
return Redirect::route('posts');
}
}
A controller is a bridge between the HTTP requests, your business logic and your presentation layer. So it should receive one request, send it to an injected object which will process it and redirect to the route (or render a view) responsible for giving feedback to a client (or user). Everything else, including validation, should happen in your repositories, services, models (MVC, yay!), etc.
But we could refactor this controller, in the hexagonal way, to reach the one-line-per-method goal:
<?php
class PostController extends Controller {
private $repository;
public function __construct(PostRepositoryInterface $repository)
{
$this->repository = $repository;
}
public function store()
{
return $this->repository->create(Input::all(), $this);
}
public function createSucceeded()
{
return Redirect::route('posts');
}
public function createFailed()
{
return Redirect::back()->withInput()->withErrors($e->all());
}
}
Basically your repository classes will use the own caller ($this) to fire the succeeded and failed methods.
Fat Repositories / Services / Models
Models are too related to your data, sometimes they are your ORM and talk directly to your database server, so, these days you'll see people use repositories and services as layers between them.
Repositories
A repository is a class that, by talking directly to your models, processes and gather the information your application needs. Your application should not be aware of what is necessary to select some information in your database, select, where, order, group by, those are things sometimes only your models should be aware of, so this is a repository:
class PostRepository implements PostRepositoryInterface {
private $model;
public function __construct(PostInterface $model)
{
$this->model = $model;
}
public function create($input)
{
return $this->model->create($input);
}
public findBySlug($slug)
{
return $this->model->where('slug', $slug)->first();
}
}
Services
Everything that doesn't belongs directly to your business logic, mostly external services, the farthest from your application code, the more decoupled you build them, the better. Creating external packages (Composer packages) for those services are a good way of decoupling them from everything else, and you if you make them framework agnostic you're entitled to receive 10 Sturgeon points. In Laravel you can create services by integrating three kind of classes:
1) Service Class(es): responsible for doing what your service must do, all your service logic goes here.
2) Service Provider: responsible for booting up your service and adding it to Laravel's IoC container so it can be ready to use at any time, but note that Laravel will only instantiate your service classes when your application really use them.
3) Facade: lets you access your service from anywhere in your application using the static (::) syntax:
Mailer::send($user->id, 'Thanks for registering', 'emails.registered');
This the Mailer service:
Service Class
<?php namespace ACR\Services\Mailer;
use Illuminate\Mail\Mailer as IlluminateMailer;
use Sentry;
class Service {
public function __construct(IlluminateMailer $mailer)
{
$this->mailer = $mailer;
}
public function send($userId, $subject, $view, $data = [])
{
return $this->mailer->queue($view, $data, function($message) use ($userId, $subject)
{
$user = Sentry::findUserById($userId);
$message->to($user->email, $user->name);
$message->subject($subject);
});
}
}
Service Provider
<?php namespace ACR\Services\Mailer;
use Illuminate\Support\ServiceProvider as IlluminateServiceProvider;
use ACR\Services\Mailer\Service as Mailer;
class ServiceProvider extends IlluminateServiceProvider {
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->bind('acr.mailer', function($app) {
return new Mailer($app->make('mailer'));
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array('acr.mailer');
}
}
Facade
<?php namespace ACR\Services\Mailer;
use Illuminate\Support\Facades\Facade as IlluminateFacade;
class Facade extends IlluminateFacade {
protected static function getFacadeAccessor() { return 'acr.mailer'; }
}
Models / ORM
Those guys should be highly swappable, today you may be using a Eloquent as your ORM, storing data in a database, but you might need to change it to something else, some foks are storing 100% of their data in Redis, so you better be prepared for a change like this by using an Interface (contract) layer between your ORM and your domain loginc and really develop for your interfaces, not your concrete classes. Taylor Otwell in his book even say that you should completely delete your models folder.
interface PostInterface {
public function all();
public function find($id);
}
class DbPost extends Eloquent implements PostInterface {
}
class RedisPost extends Eloquent implements PostInterface {
}
The idea behind this is to swap implementations easily, so in Laravel you can use the IoC container to tell Laravel which implementation you are using:
App::bind('PostInterface', 'DbPost');
So, if you have a Repository is using your PostInterface:
class PostRepository implements PostRepositoryInterface {
private $model;
public function __construct(PostInterface $model)
{
$this->model = $model;
}
}
Laravel IoC container will automatically instantiate this repository with an instance of DbPost. And if you ever need to change it to Redis, you just need to change one line:
App::bind('PostInterface', 'RedisPost');
Views / Presenters
The dumbest the awesomer.
Views
Views should be responsible only for displaying information. Views should not be aware of your models, services, repositories, or anything else in your system. Views should be editable by webesigners so, the more code you have on them, the more bugs your non-php-programmer-designer will add to them. Your controller should gather the information from your repositories and pass them to your views:
<?php
class PostController extends Controller {
private $repository;
public function __construct(PostRepositoryInterface $repository)
{
$this->repository = $repository;
}
public function index()
{
return View::make('posts.index')->with('posts', $this->repository->getPaginated());
}
}
And the only responsibility of your view should be show that data:
#extends('layout')
#section('contents')
<ul>
#foreach($posts as $post)
<li>
{{ $post->title }} - {{ $post->author }} - {{ $post->published_at }}
</li>
#endforeach
</ul>
{{ $users->links() }}
#stop
Presenters
How do you format your data? You write raw properties in your views, but you should, behind the scenes, be using presenters to, yeah, present your data. Presenters usually use the Decorator Design Pattern to format your data to be presented in your pages. This is an example using Shawn McCool's LaravelAutoPresenter:
<?php namespace App\Presenters;
use McCool\LaravelAutoPresenter\BasePresenter;
class Post extends BasePresenter {
public function __construct(UserModel $user)
{
$this->resource = $user;
}
public function author()
{
return $this->resource->author->name;
}
public function published_at()
{
return $this->date($this->resource->created_at);
}
public function dateTime($date)
{
return \Carbon\Carbon::createFromFormat('d-m-Y', $date, 'Sao_Paulo/Brazil')
->toFormattedDateString();
}
}
Related Books
Taylor Otwell's Laravel: From Apprentice To Artisan
Chris Fidao's Implementing Laravel

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
}
}
}

zend validate user for a specific controller?

HI i would like to know how to validate a users for a specific controller, so that we can check that a specific users is authenticate before accessing resources of a controller?
you should take a look at Zend_Auth and Zend_Acl Component.
Zend_Auth is responsible for assigning and managing authentication of the user.
Zend_Acl is responsible for managing different permissions and roles for different resources.
here is the tutorial explaining how you can implement Zend_Auth.
http://akrabat.com/zend-auth-tutorial/
and the below tutorial explains about Zend_Auth/Zend_Acl
http://devzone.zend.com/844/zend_acl-zend_auth-example-scenario/
Lets says for a specific controller in controller folder we have CashoutController. Before a user accessing this controller we will authenticate the users as below with make use of custom library.
<?php
class CashoutController extends Zc_Controller_Action_User
{
public function init()
{
/* Initialize action controller here */
parent::init();
}
// rest code goes here
}
now we defined new library name Zc
<?php
class Zc_Controller_Action_User extends Zc_Controller_Action
{
public function init()
{
parent::init();
$this->validateAccess();
}
private function validateAccess()
{
$auth = Zend_Auth::getInstance();
if (is_null($auth->getIdentity())) {
$this->_helper->redirector('index', 'index');
}
}
}
where we define controller action library as
<?php
class Birdtoldme_Controller_Action extends Zend_Controller_Action
{
}
hope this is has been an informative for you.

Abstract class to handle permission-based functions

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
}
}
}

Categories