Laravel How not to Rewrite the Same code again - laravel

I have a model, called Tours and controller ToursController which uses restful methods (index, show, store, edit, update etc).
Now I have this code:
$names = request()->get('names');
$lastnames = request()->get('lastnames');
$hotels = request()->get('hotel');
both in Store and Update. So i duplicate the same code twice. And this is only one exmaple of duplicated code.
I want to create a function "getEverythingFromRequest()"
which I can use in both Store and Update methods. Something like:
public function store (Request $request) {
getEverythingFromRequest();
dd($names[3];
}
public function store (Request $request) {
getEverythingFromRequest();
dd($hotels[2];
}
How can I do it? Globally, how can I avoid re-writing the same code in Controller?

There are a bunch of ways to solve this. One way would be to create a repo that extracts the arrays from your request. (I updated my code to use injection).
Controller
public function store (GuestsRepository $repo, Request $request) {
dd($repo->names);
}
Repository
<?php
namespace App;
class GuestsRepository
{
public $names;
public $lastnames;
public $hotels;
public function __construct(){
$this->names = request()->get('names');
$this->lastnames = request()->get('lastnames');
$this->hotels = request()->get('hotel');
}
}

Related

How to pass data to all views in Laravel 5.6?

I have two controllers. StudentController and TeacherController. I have a variable $chat which I want to pass in all the views of StudentController and TeacherController. The $chat will contain different data for both these controllers.
I searched and found ways, but I am getting empty data. I am doing it like this.
<?php
namespace App\Http\Controllers;
use View;
class StudentController extends Controller {
public function __construct()
{
$this->middleware('auth')->except(['home']);
$this->middleware('access')->except(['home']);
$chats = studentChat();
View::share('chats', $chats);
}
So, here I am printing and it is returning an empty array, but when I use the same in a function the array contains data. What is wrong here? Can anyone please help?
What I tried:
public function boot()
{
View::composer('*', function ($view) {
$chats = Cache::remember('chats', 60, function () {
if(Auth::user()->user_type() == config('constant.student'))
{
return studentChat();
}
else
{
return teacherChat();
}
});
$view->with('chats', $chats);
});
}
If you use View::share your share data to ALL your view, if you need to add data to few different views you may do this:
Create blade file(chat.blade.php for your case), and put your variables:
<? $chats = studentChat(); ?>
Include this file to the begining of your views where your need this 'global' varables:
//begin of your blade file
#include('chat')
//some code
{{ $chat->channel }}
Sharing Data With All Views
Occasionally, you may need to share a piece of data with all views that are rendered by your application. You may do so using the view facade's share method. Typically, you should place calls to share within a service provider's boot method. You are free to add them to the AppServiceProvider or generate a separate service provider to house them:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$chats = studentChat();
View::share('chats', $chats);
}
public function register()
{
//
}
}
So, what I did was in the AppServiceProvider class, in the boot function I added this.
View::composer('*', function ($view) {
if(!\Auth::check())
{
return;
}
$userType = \Auth::user()->user_type ;
if($userType == config('constant.student'))
{
$chats = studentChat();
}
else if($userType == config('constant.teacher'))
{
$chats = teacherChat();
}
$view->with('chats', $chats);
});
You can pass data to the view Like.
return View::make('demo')->with('posts', $posts);
For more details visit article : Introduction to Routing in Laravel
write your query in boot method in appServiceProvider like,
View::composer('*', function ($view) {
$share_query = Cache::remember('share_query', 60,function () {
return App\User::all();
});
$view->with('share_query', $share_query);
});
Your final solution is ok, but not the cleanest possible.
Here is what i would do.
Define a class with a single function that contains your logic and return $chats, that way you will encapsulate your logic properly and keep your service provider boot method clean.
Then you have 2 options:
Inject your class in the boot() method of the service provider you use, then call its function and uses View::share. Should looks like :
public function boot(ChatResolver $chatResolver)
{
$chats = $chatResolver->getChats();
View::share(compact('chats));
}
If you only use $chats variable in a signe view or partial (like a part of layout), you can also inject the class you defined directly in the view.
Here is a link to Laravel doc regarding that.
In some cases it might be the easiest solution.

Setting getKeyRouteName dependant on route (web or api)

Tried looking for the answer to this everywhere but having no luck so far...
Basically I want my web route to use a slug for its URL, but I want to use ID for the API route. So...
http://myurl.com/chapter/my-chapter-slug
and
http://myurl.com/api/chapter/1234
Have tried various combinations of things in the getRouteKeyName method (if(Request::route()->named('myapiroute'), if(Request::isJson() etc...) but I think these might be being checked against the page it's running on, rather than the route I'm trying to generate?
I'm thinking maybe I need to extend the base model to have a separate one to use with my API maybe?
So I'd have...
class Chapter extends Model
{
public function getRouteKeyName()
{
return 'slug';
}
....
}
and then...
class ApiChapter extends Chapter
{
public function getRouteKeyName()
{
return 'id';
}
....
}
But not sure how I'd structure this in the most "Laravel" way? Or is there a better/tidier solution?
define your route for example like
Route::get('chapters/{chapter}','ChapterController#show'); // find by slug
Route::get('api/chapters/{chapter}','ApiChapterController#show'); // find by id
for web controller
class ChapterController extends Controller
{
public function show(Request $request,$slug)
{
$instance = Model::whereSlug($slug)->first();
}
}
for api
class ApiChapterController extends Controller
{
public function show(Request $request,$id)
{
$instance = Model::find($id);
}
}
You can define 2 different routes for that but unfortunatelly you will not be able to use model binding and you will have to look for the model like:
public function show(Request $request,$slug) {
$instance = Model::whereSlug($slug)->first();
}
as shown below: https://stackoverflow.com/a/48115385/6525417

recall the construct in codigniter

How to recall the construct as it contains all the required data for the page?
class Abc extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('xyz_m');
$this->data['info'] = $this->xyz_m->get(); //get data
}
public function 123()
{
/*view page code*/
}
public function 456()
{
/*insert code here*/
$this->123(); // redirect, need to load 123() with updated data from construct.
}
}
So, how do you make the __construct initiate again so you get a new updated results from database?
You should name your methods with letter first i.e. there is convention for method names uses descriptive words getProducts() or get_books or you will get PHP error for using numbers as method names. So in your case method names should be like a123() or b_456().
Second thing, regarding your need in question, since you assign data from DB using model to array $this->data, you would use it like:
class Abc extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('xyz_m');
$this->data['info'] = $this->xyz_m->get(); //get data
}
public function a123()
{
$this->load->view('a123_view', $this->data);//loading file APPPATH . 'a123_view.php' and passing created array to it
}
public function b_456()
{
/*insert code here*/
$this->a123(); // redirect, need to load 123() with updated data from construct.
}
}
In your APPPATH . 'a123_view.php':
<?php var_dump($info);//here you would call key of array you passed from controller as variable ?>
Check basics in CodeIgniter documentations. All this is described in General Topics section.

CodeIgniter - Replace redunant JSON conversion

I recently started using Codeigniter after having a structural problem in one of my Ajax-heavy applications. (You can read up on it if you want in my previous question)
I have a fairly short question. Currently I am making a lot of Ajax requests to different controllers. I open the controllers like this:
public function __construct()
{
parent::__construct();
$this->output->set_content_type('application/json');
}
And at the end of every function I do the following:
$this->returnValue['result'] = "ReturnedInfo";
$this->returnValue = json_encode($this->returnValue);
$this->output->set_output($this->returnValue);
The code is pretty clear in itself, but I don't want to keep repeating myself. The codeigniter manual says to do the following:
$this->output
->set_content_type('application/json')
->set_output(json_encode(array('foo' => 'bar')));
But I would still be repeating myself. Also, I don't want to add a function to every controller that does this, even if it does decrease redundancy.
Since all of my controllers return JSON, is there a way to set this globally in a config file maybe, or in any other way?
TL;DR I have this same piece of code in every controller/function. Since the output type is always the same, just not the result, is there a way to automate this process across every controller/function?
Create an Ajax_Controller that extends MY_Controller that extends CI_Controller.
The Ajax Controller will then inherit from both Controllers.
class Ajax_Controller extends MY_Controller
{
public function __construct()
{
parent::__construct();
if(!$this->input->is_ajax_request()) return show_error('Invalid Request');
}
public function jsonOutput($json)
{
//some data checking here....
return $this->output
->set_content_type('application/json')
->set_header("HTTP/1.1 200 OK")
->set_output($json);
}
}
-
class User extends Ajax_Controller
{
public function __construct()
{
parent::__construct();
}
public function userMethod()
{
$json = json_encode(array(
'' => ''
));
$this->jsonOutput($json);
}
}
Extend your controllers from your own base class rather than CI_Controller and put your repeatedly-used function(s) and constructor code in there. Something like:
class BaseController extends CI_Controller {
protected function index() {
$this->returnValue['result'] = "ReturnedInfo";
$this->returnValue = json_encode($this->returnValue);
$this->output->set_output($this->returnValue);
}
}
class Specific extends BaseController {
public function index() {
//do controller-specific stuff
parent::index();
}
}
I abstract this further if I have groups of controllers with shared code; for example, if I had a bunch of controllers that require the user to be logged-in I create AuthenticatedController, which extends BaseController and add session checks etc.

Codeigniter updating records in db table

I want to change a specific record in the database using codeigniter. The url should be like this mysite.com/users/edit/10.
Here the user having id=10 is being edited
users is the controller name and edit is a method.
Usually I do in this way
//code of the rest of controller
.....
function edit(){
$uid =$_REQUEST['uid'];
//database update code
}
...
Where a form is being posted deliberately to change the record
You're not clear at all on what you want, I just can give you some pointers.
In CI, you don't need (don't have to) use superglobals to access url parameters. It has a native system to manage uri segments, which became automatically accessible without the need to call them; they're available as arguments of the method you're accessing.
So, in a url like yours, mysite.com/users/edit/10, you'll have
Controller:
class Users extends CI_Controller {
public function edit($uid)
{
// $uid is automatically passed to this method and is already available
// here you do your operations
//for. ex.
$this->load->model('user_model');
$this->user_model->update_user($uid);
}
}
Model:
class User_model extends CI_Model {
function __construct()
{
parent::__construct();
}
function update_user($id)
{
$this->db->where('id',$id);
$fields = array('field1' => 'value1','field2' => 'value2'...);
$this->db->update('users',$fields);
}
}
If you provide further information I could expand my answer.

Resources