I'm trying to understand how to use "fat model, skinny controller" in Laravel 5.2. Basically, I mostly understand the why, and the what, but not the how. I've been Googling for a while, and I have found several pages describing why (and some pages describing why not) and what, but no pages that makes it easy to understand how you create a fat model with skinny controllers.
I have created a extremely basic Todo-list, no login or validation, just the most basic todo-note functionality. This application basically uses "skinny model, fat controllers" and I want to rewrite the app so that it uses "fat model, skinny controllers" instead.
I have three tables in the MySQL-database:
users
id int(10)
uname varchar(255)
email varchar(255)
password varchar(60)
projects
id int(10)
pname varchar(255)
notes
id int(10)
user_id int(10)
project_id int(10)
content text
time_created timestamp
time_deadline timestamp
completed tinyint(1)
removed tinyint(1)
When I created the migrations for the tables, I used $table->foreign('user_id')->references('id')->on('users'); and $table->foreign('project_id')->references('id')->on('projects'); for the notes table migration. For some reason it did not work, so in the database notes.user_id and notes.project_id are not foreign keys to users.id and projects.id, which was the idea from the beginning. I'm guessing that it doesn't really matter for my questions below, but if it does, someone please tell me so I can try to fix that.
I have the following models (doc blocks removed)
app\User.php:
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function notes()
{
return $this->hasMany(Note::class);
}
}
app\Project.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
public function notes()
{
return $this->hasMany(Note::class);
}
}
app\Note.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Note extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function project()
{
return $this->belongsTo(Project::class);
}
}
I have the following controllers (doc blocks removed)
app\Http\Controllers\UserController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\User;
use Response;
class UserController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$users = User::orderBy('uname', 'asc')->get()->toArray();
$response = [];
foreach ($users as $user) {
$this_row = array(
'id' => $user['id'],
'name' => $user['uname'],
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
}
app\Http\Controllers\ProjectController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Project;
use Response;
class ProjectController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$projects = Project::orderBy('pname', 'asc')->get()->toArray();
$response = [];
foreach ($projects as $project) {
$this_row = array(
'id' => $project['id'],
'name' => $project['pname'],
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
}
app\Http\Controllers\NoteController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Note;
use App\User;
use App\Project;
use Input;
use Response;
use Redirect;
class NoteController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$notes = Note::where('removed', 0)
->orderBy('time_created', 'asc')->get()->toArray();
$response = [];
foreach ($notes as $note) {
$user = User::find($note['user_id']); // Username for note
$project = Project::find($note['project_id']); // Project name
$this_row = array(
'id' => $note['id'],
'user' => $user['uname'],
'project' => $project['pname'],
'content' => $note['content'],
'completed' => $note['completed'],
'created' => $note['time_created'],
'deadline' => $note['time_deadline']
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
public function destroy(Request $request)
{
try {
$statusCode = 200;
$note = Note::find($request->id);
$note->removed = 1;
$note->save();
} catch (Exception $e) {
$statusCode = 400;
} finally {
return $statusCode;
}
}
public function edit($request)
{
try {
$statusCode = 200;
$note = Note::find($request);
$response = array(
'id' => $note['id'],
'content' => $note['content'],
'completed' => $note['completed'],
'deadline' => $note['time_deadline']
);
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
public function update(Request $request)
{
try {
$statusCode = 200;
$note = Note::find($request->id);
$note->content = $request->content;
$note->time_deadline = $request->deadline;
if ($request->completed == "true") {
$note->completed = 1;
} else {
$note->completed = 0;
}
$note->save();
} catch (Exception $e) {
$statusCode = 400;
} finally {
return $statusCode;
}
}
public function store(Request $request)
{
try {
$statusCode = 200;
$note = new Note;
$note->user_id = $request->user;
$note->project_id = $request->project;
$note->content = $request->content;
$note->time_deadline = $request->deadline;
$note->save();
} catch (Exception $e) {
$statusCode = 400;
} finally {
return $statusCode;
}
}
}
Finally, this is my app/Http/routes.php (comments removed)
<?php
Route::get('/', function () {
return view('index');
});
Route::get('/notes', 'NoteController#index');
Route::get('/notes/{id}', 'NoteController#edit');
Route::delete('/notes', 'NoteController#destroy');
Route::put('/notes', 'NoteController#store');
Route::post('/notes', 'NoteController#update');
Route::get('/projects', 'ProjectController#index');
Route::get('/users', 'UserController#index');
Route::group(['middleware' => ['web']], function () {
//
});
The complete code can be found at my GitHub here.
I'm using Angular to receive the JSON sent by the controllers. This works fine for my current page but as you can see, my controllers have a lot of logic, which I would like to move to the model. I don't understand how I do this, so here's my questions:
Which additional files should I create?
Where should they be located?
What do I need in those files except the logic that currently is in the controllers?
How should I rewrite the controllers to handle the data from the models?
Your skinny controller could be the following, which will do the same what you did:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Project;
class ProjectController extends Controller
{
public function index()
{
$projects = Project::orderBy('pname', 'asc')->get(['id', 'name']);
return response()->make($projects);
}
}
But as Fabio mentioned, if you want to go further, checkout repositories. Here is a good article: https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/
In most cases I'm wrapping repositories into services to create the business logic. Controllers just handle routing, and models only contains relations or mutators and accessors. But it could differ by development methods.
Also, don't make db queries in foreach loops, take the advantage of Eloquent with, forexample:
$notes = Note::where('removed', 0)
->with(['user', 'project'])
->orderBy('time_created', 'asc')->get();
And you can access, like this:
foreach($notes as $note)
{
echo $note->user->uname;
}
Related
I am trying to get lists from mailchimp based on apikey which is stored in database against user_id. I am getting all the lists based in apikey which is stored in my config file in laravel. But here i want to get lists from mailchimp based on api key stored in database.
The code I am using to get all the lists based on apikey from config file is:
public function getLists(Request $request)
{
$request->user()->id;
$result = MailchimpFacade::request( 'lists', ['fields' => 'lists.id,lists.name'] );
$resultArray = ['status' => 1, 'message' => 'Lists appear successfully!', 'dataArray' => $result];
return \Illuminate\Support\Facades\Response::json($resultArray, 200);
}
Here i want to get lists from mailchimp based on apikey stored in database.
You time and help will be highly appreciated!
public function getLists (Request $request)
{
$request->user()->id;
$mc = new MailChimp($request->input('api_key'));
$result = $mc->get('/ping');
return \Illuminate\Support\Facades\Response::json($result, 200);
}
<?php
namespace App\Http\Controllers;
use App\APIKEY;
use DrewM\MailChimp\MailChimp;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Validator;
class ApiController extends Controller
{
public function getLists (Request $request)
{
$request->user()->id;
$mc = new MailChimp($request->input('api_key'));
$result = $mc->get('/ping');
return \Illuminate\Support\Facades\Response::json($result, 200);
}
}
public function getLists(Request $request)
{
Auth::user()->id;
$apikey = $request->input('api_key');
DB::table('apikey')
->where('api_key','=', $apikey)
->get();
if($apikey){
$mc = new MailChimp($apikey);
$mailchimp_ping = $mc->get('lists',['fields' => 'lists.id,lists.name'] );
return \Illuminate\Support\Facades\Response::json($mailchimp_ping, 200);
}
else
{ $errorResponse = [
'message' => 'Lists not found!',
'error' => '401'
];
return Response::json( $errorResponse);
}
}
Use DrewM\MailChimp\MailChimp instead of Facade.
use DrewM\MailChimp\MailChimp;
$mc = new MailChimp($apikey);
$result = $mc->get('lists');
print_r($result);
Full Controller, Edit it according to your need-
<?php
namespace App\Http\Controllers;
use DrewM\MailChimp\MailChimp;
class ApiController extends Controller
{
public function authenticateApiKey()
{
$mc = new MailChimp('48cda414960152d55f97a8f44e28ea20-us17');
$mailchimp_ping = $mc->get('lists');
return \Illuminate\Support\Facades\Response::json($mailchimp_ping, 200);
}
}
See this for further details.
Hello i have a form which sets the date of voting start and stop, today I started to get this information on my screen. Could anyone tell me what does it mean ?
This functionality uses 2 php files.
MakeVoteController in which i take the date from form and then do Carbon::create and put them into database and there's function in my VotingStatus model. It is checking if the current date is in between begin and end date then it returns voting_status(started or stopped)
VOTINGMGMT CONTROLLER
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use DB;
use App\Http\Requests;
use Illuminate\Support\Facades\Input;
use Carbon\Carbon;
class VotingMgmtController extends Controller
{
public function start()
{
self::setStart();
return view('panel.startvoting');
}
public function stop()
{
self::setStop();
return view('panel.stopvoting');
} //
public function setDateView()
{
return view('panel.startvoting');
}
public function setDate(Request $request)
{
$rok_start = Input::get('rok');
$miesiac_start = Input::get('miesiac');
$dzien_start = Input::get('dzien');
$godzina_start = Input::get('godzina');
$minuta_start = Input::get('minuta');
$rok_stop = Input::get('rok_end');
$miesiac_stop = Input::get('miesiac_end');
$dzien_stop = Input::get('dzien_end');
$godzina_stop = Input::get('godzina_end');
$minuta_stop = Input::get('minuta_end');
$begin_date = Carbon::create($rok_start,$miesiac_start,$dzien_start,$godzina_start,$minuta_start,59,'Europe/Warsaw');
$stop_date = Carbon::create($rok_stop,$miesiac_stop,$dzien_stop,$godzina_stop,$minuta_stop,59,'Europe/Warsaw');
$now = Carbon::now('Europe/Warsaw');
//Set begin and end date in database
DB::table('voting_status')
->where('id',1)
->update(['voting_start_date' => $begin_date]);
DB::table('voting_status')
->where('id',1)
->update(['voting_end_date' => $stop_date]);
return redirect()->route('set_date')->with('success','Ustawiono datę rozpoczęcia i zakończenia głosowania');
}
public function setEndDate()
{
}
private function setStart()
{
try
{
DB::table('voting_status')
->where('id',1)
->update(['status' => 'started']);
}
catch(\Illuminate\Database\QueryException $ex)
{
return view('info.dash_service_unavailable');
}
}
private function setStop()
{
try
{
DB::table('voting_status')
->where('id',1)
->update(['status' => 'stopped']);
}
catch(\Illuminate\Database\QueryException $ex)
{
return view('info.dash_service_unavailable');
}
return true;
}
private function checkDate()
{
}
}
VOTINGSTATUS MODEL
<?php
namespace App;
use DB;
use PDO;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class VotingStatus extends Model
{
protected $table = "voting_status";
//check table VotingStatus whether started or not
function checkStatus()
{
/*query database about status of voting and
print output */
DB::setFetchMode(PDO::FETCH_ASSOC);
$begin_date = DB::select('select voting_start_date from voting_status where id=1 ');
$end_date = DB::select('select voting_end_date from voting_status where id=1');
$now = Carbon::now('Europe/Warsaw');
$begin_var;
$end_var;
foreach($begin_date as $key => $value)
{
$begin_var= (string)$value['voting_start_date'];
echo $begin_var;
}
foreach($end_date as $key => $value)
{
$end_var= (string)$value['voting_end_date'];
echo $end_var;
}
$carbon_start = Carbon::parse($begin_var,'Europe/Warsaw');
$carbon_stop = Carbon::parse($end_var,'Europe/Warsaw');
if(($now->gt($carbon_start)) && ($now->lt($carbon_stop)))
{
try
{
DB::table('voting_status')
->where('id',1)
->update(['status' => 'started']);
}
catch(\Illuminate\Database\QueryException $ex)
{
dd("Upss start");
}
}
else
{
try
{
DB::table('voting_status')
->where('id',1)
->update(['status' => 'stopped']);
}
catch(\Illuminate\Database\QueryException $ex)
{
dd("Upss stop");
}
}
DB::setFetchMode(PDO::FETCH_CLASS);
$db_stat = DB::table('voting_status')->where('id',1)->first();
$status = $db_stat->status;
return $status;
}
}
FORM
Error has been fixed. After uploading newer version of application on the server there still was old version of web.php. In mentioned web.php my form submit was handled by function
set_date(Request $request)
{
return $request;
}
Now everything works
i have created a method to fetch only the soft deleted lessons in my LessonsController
i'm not getting what should be the route my lessoncontroller
<?php
namespace App\Http\Controllers;
use Response;
use App\lesson;
use Illuminate\Http\Request;
use App\Acme\Transformers\LessonTransformer;
use Illuminate\Support\Facades\Input;
class LessonsController extends ApiController
{
protected $lessonTransformer;
function __construct(LessonTransformer $lessonTransformer)
{
$this->lessonTransformer = $lessonTransformer;
}
//fetch all and pass a metadata 'data'
public function index()
{
$lessons = Lesson::all();
return $this->respond([
'data' => $this->lessonTransformer->transformCollection($lessons->all())
]);
}
//delete a lesson by id
public function destroy($id)
{
$dlesson = Lesson::find(input::get('id'));
if(! $dlesson) {
return $this->respondNotFound();
}
$dlesson->delete();
return $this->respondDeleted('Lesson deleted successfully');
}
public function deletedLessons()
{
$deleted_lessons = Lesson::onlyTrashed()->get();
return $this->respond([
'data' => $this->lessonTransformer->transformCollection($lessons->all())
]);
}
}
i have tried with a deleted record like
http://localhost:8000/api/v1/lessons/11
Thank You
Make sure:
You've used softDeletes() method in migration and executed this migration
You're using SoftDeletes trait in the model
You've added deleted_at to $dates property in the model
https://laravel.com/docs/5.3/eloquent#soft-deleting
After doing all that your query will work just fine and will return only soft deleted lessons:
$deleted_lessons = Lesson::onlyTrashed()->get();
I have opted out of using Laravel's built in User Authentication due to my application's requirements. We rely on a Third Party SSO to authenticate our users, and I was unable to get Socialite to work with their SSO, so I am having to custom build a Controller to handle the authentication process. The Controller is performing b-e-a-utifully up until the part when I need to redirect the user from the Callback Route & Controller to the Member Route & Controller. It won't redirect. Period. I have tried every method I know how to redirect to another route from within the controller and it will not work.
Here is my custom AuthController for Laravel 5.3:
<?php
namespace App\Http\Controllers;
use App\User;
use Curl\Curl;
use App\Http\Controllers\PhealController as Pheal;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\Redirector;
class AuthController extends Controller
{
protected $curl;
private $data;
public function __construct ()
{
$this->curl = new Curl();
$this->pheal = new Pheal();
$this->data = [];
}
public function sendToSSO()
{
$url = env('EVE_SSO_LOGIN')."?response_type=code&redirect_uri=".env('EVE_CALLBACK_URL')."&client_id=".env('EVE_CLIENT_ID')."&scope=".env('EVE_SCOPES');
return redirect($url);
}
public function handleCallback(Request $request)
{
$this->curl->setHeader('Authorization', "Basic ". base64_encode(env('EVE_CLIENT_ID').":".env('EVE_SECRET')));
$this->curl->setHeader('Content-Type', "application/x-www-form-urlencoded");
$this->curl->setHeader('Host', "login.eveonline.com");
$this->curl->post('https://login.eveonline.com/oauth/token', [
'grant_type' => 'authorization_code',
'code' => $request->code
]);
$response = $this->curl->response;
if (isset($response->error)) {
throw new \Exception($response->error_description);
}
$this->data = [
'accessToken' => $response->access_token,
'refreshToken' => $response->refresh_token
];
$this->verifyToken();
}
public function verifyToken ()
{
$this->curl->setHeader('User-Agent', "David Douglas ddouglas#douglaswebdev.net");
$this->curl->setHeader('Authorization', "Bearer ". $this->data['accessToken']);
$this->curl->setHeader('Host', "login.eveonline.com");
$this->curl->get('https://login.eveonline.com/oauth/verify');
$response = $this->curl->response;
if (isset($response->error)) {
throw new \Exception($response->error_description);
}
$this->data['characterID'] = $response->CharacterID;
$this->data['characterName'] = $response->CharacterName;
$this->data['accessTokenExpire'] = $response->ExpiresOn;
try {
$characterInfo = $this->pheal->call('eve', 'CharacterInfo', ['characterID' => $this->data['characterID']])['result'];
} catch (\Exceoption $e) {
abort(404);
}
if (!isset($characterInfo['allianceID'])) {
abort(403, "Care Factor Alliance Members Only. Sorry :-(");
}
if ($characterInfo['allianceID'] !== env('CF-ALLIANCE-ID')) {
abort(403, "Care Factor Alliance Members Only. Sorry :-(");
}
$this->data['corporationID'] = $characterInfo['corporationID'];
$this->data['corporation'] = $characterInfo['corporation'];
$user = User::find($this->data['characterID']);
if ($user) {
$this->updateUserAndLogin($user);
} else {
$this->createNewUserAndLogin();
}
}
private function getData()
{
return $this->data;
}
public function createNewUserAndLogin()
{
dd('To be Created');
}
public function updateUserAndLogin($user)
{
$user->corporationID = $this->data['corporationID'];
$user->corporation = $this->data['corporation'];
$user->accessToken = $this->data['accessToken'];
$user->refreshToken = $this->data['refreshToken'];
$user->accessTokenExpire = $this->data['accessTokenExpire'];
$user->save();
//Auth::login($user);
return redirect('member/dashboard/');
}
}
I have also tried:
return redirect()->route('member.dashboard');
With no luck.
You mean the $this->createNewUserAndLogin()? Maybe trying return $this->updateUserAndLogin($user); and return $this->verifyToken(); so you return the response on the main method of the route?
I want to retrieve this.
all plan.
all plan without Trial Day.
all plan only trial day.
but i don't know the procedure for take a filter on api Stripe.
https://stripe.com/docs/api#plans
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Stripe\Plan;
use Stripe\Stripe;
class PlanController extends Controller {
public function index(Request $request)
{
Stripe::setApiKey(env('STRIPE_SECRET'));
$param = ['limit' => 20];
$opt = ['livemode' => false];
$plans = Plan::all($param,$opt);
return plans;
}
}
After you fetch all, you can filter it through php
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Stripe\Plan;
use Stripe\Stripe;
class PlanController extends Controller {
public function index(Request $request)
{
Stripe::setApiKey(env('STRIPE_SECRET'));
$param = ['limit' => 20];
$opt = ['livemode' => false];
$all_plans = Plan::all($param,$opt);
$trial_plans = [];
$no_trial_plans = []
foreach ($all_plans['data'] as $plan) {
if ($plan['trial_period_days'] == null) {
$no_trial_plans[] = $plan;
}
else {
$trial_plans[] = $plan;
}
}
return [$all_plans, $trial_plans, $no_trial_plans];
}
}