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