How to use Laravel Cache::remember with a callback function - laravel

I would like to reference a private function as the third parameter to the Cache::remember function.
Instead of this (try{}catch() was removed for a cleaner code):
class ApiController extends Controller
{
public function index(){
$data = Cache::remember('dataKey', 60, function () {
return Model::multipleMethodsHere()->get();
});
return response()->json($data,200);
}
}
I'd like to do this:
class ApiController extends Controller
{
public function index(){
$data = Cache::remember('dataKey', 60, $this->getIndex());
return response()->json($data,200);
}
private function getIndex(){
return Model::....->get();
}
}
I got this error if I try to reference a private function.
Argument 3 passed to Illuminate\\Cache\\Repository::remember() must be an instance of Closure, instance of Illuminate\\Database\\Eloquent\\Collection given
Is it possible ? If yes, how should I do ?

Based on comments in the discussion to the OP, re-strategize the Cache:remember to be a part of the getIndex function like:
class ApiController extends Controller
{
public function index(){
$data = $this->getIndex();
return response()->json($data,200);
}
private function getIndex(string $dataKey = 'dataKey', int $time = 60){
return Cache::remember($dataKey, $time, function () {
return Model::....->get();
})
}
}

Related

Laravel - how can I return view from another function

Route:
Route::controller(PublicController::class)->group(function () {
Route::get('/index', 'index')->name('public.index');
});
View:
index.blade.php
wrong_browser.blade.php
In controller, this way is ok:
class PublicController extends Controller
{
public function index(Request $request)
{
if(is_wrong_browser)
return view(public.wrong_browser);
return view('public.index');
}
}
But how can I return view from another function, like this, without making a new route:
class PublicController extends Controller
{
public function index(Request $request)
{
$this->CheckBrowser();
return view('public.index');
}
public function CheckBrowser()
{
if(is_wrong_browser)
return view(public.wrong_browser);
}
}
You can use the method redirect.
return redirect()->route('index');
You could use middleware which you either define globally, or on specific routes.
class CheckUserActive
{
public function handle($request, Closure $next)
{
// determine value of $is_wrong_browser
$is_wrong_browser = true;
if ($is_wrong_browser) {
return redirect()->route('is-wrong-browser-route');
}
return $next($request);
}
}
It is bad practice to return a view from middleware instead redirect your user to another route.
Alternatively, you could have a base Controller that your Controllers extend which has the checkBrowser function defined on it and the extending Controllers therefore have access to:
class WrongBrowserController extends \App\Http\Controllers\Controller
{
public function checkBrowser()
{
// determine value of $is_wrong_browser
$is_wrong_browser = true;
if ($is_wrong_browser)
{
return view('wrong-browser-view');
}
}
}
class PublicController extends WrongBrowserController
{
public function index(Request $request)
{
$this->checkBrowser();
return view('index');
}
}

Call to a member function hasAccessOrFail() on null error when using backpack in Laravel

I've been using backpack in Laravel but I want to replace action-domain-responder architecture with MVC.So I've created an Action which my route refers like below:
Route::get('post',[
'as' => 'post.index',
'uses' => 'Core\Post\Actions\ApiGetListOfPostsAction',
'operation' => 'list'
]);
class ApiGetListOfPostsAction extends BaseAction implements IAction
{
private $service;
public function __construct(ApiGetListOfPostsService $service)
{
$this->service = $service;
}
public function __invoke(Request $request): mixed
{
$data = $this->service->process();
return response()->json($data);
}
}
and my service has this code:
class ApiGetListOfPostsService extends CrudController
{
use ListOperation, CreateOperation, DeleteOperation, UpdateOperation;
public function setup()
{
CRUD::setModel(\App\Models\Post::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/post');
CRUD::setEntityNameStrings('post', 'posts');
}
protected function setupListOperation()
{
CRUD::column('title');
CRUD::column('content');
}
public function process()
{
return $this->index();
}
}
I've extended CrudController in my service class but I've got this error:
Call to a member function hasAccessOrFail() on null
which related to the ListOperation Trait and this code:
public function index()
{
$this->crud->hasAccessOrFail('list');
}
I need to send all requests to the Service class. How can I pass requests to the service class?
When I deleted middleware from CrudController I have no problem.
$this->middleware(function ($request, $next) {
$this->crud = app()->make('crud');
$this->crud->setRequest($request);
$this->setupDefaults();
$this->setup();
$this->setupConfigurationForCurrentOperation();
return $next($request);
});
I think your Action is missing something.
When using inheritance from a parent class, it might help to put this line in your constructor.
public function __construct(ApiGetListOfPostsService $service)
{
parent::__construct(); // <- Subclass constructor
$this->service = $service;
}
Doc: https://www.php.net/manual/en/language.oop5.decon.php

Laravel trait crud controller with request validation and resources

I'm trying to refactor my code to be more reusable.
I created a trait CrudControllerTrait to implement the index,show,store,update,destroy methods.
But I found 2 problems:
BrandController.php
public function store(BrandNewRequest $request)
{
$requestData = $request->validated();
return new BrandResource($this->brands->store($requestData));
}
ProductController.php
public function store(ProductNewRequest $request)
{
$requestData = $request->validated();
return new ProductResource($this->products->store($requestData));
}
The trait method would be:
public function store(xxxxx $request)
{
$requestData = $request->validated();
return new xxxxxResource($this->repository()->store($requestData));
}
Problem1: The hint type. How can I abstract them? If I remove it shows that errror:
"message": "Too few arguments to function App\\Http\\Controllers\\BrandController::store(), 0 passed and exactly 1 expected"
Problem2: Return the resource. How can create the new resource? On the collection I can solve it doing this:
public function index()
{
$models = $this->repository()->index();
return $this->resource()::collection($models);
}
The resource is on the controller who uses the trait:
public function resource()
{
return BrandResource::class;
}
But with single resource didn't know how to do it...
The idea is, that I have so much controllers using the same pattern: BrandController, ProductController, etc. I'd love to reuse these 5 crud methods on the same trait...
The only way I found is creating an abstract method.
trait CrudRepositoryTrait
{
abstract function model();
public function index()
{
return $this->model()::with($this->with())->get();
}
public function find($id)
{
return $this->model()::findOrFail($id);
}
public function store($data)
{
$request = $this->dtoRequest($data);
return $this->model()::create($request);
}
(...)
}
And then, an example how to use this treat:
class ProductRepository implements ProductRepositoryContract
{
use CrudRepositoryTrait;
function model()
{
return Product::class;
}
(...)
}
By this way I could reuse a lot of code.

How to get model relations in Laravel?

I would like to get the model relations, in array;
My model look like:
class User extends Model
{
public function profile() {
return $this->haOne(Profile::class);
}
public function settings() {
return $this->morphOne(Settings::class, 'settingsable');
}
public function addresses() {
return $this->hasMany(Addresses::class);
}
}
And my code:
$user = User::with(['profile', 'settings', 'addresses'])->find(1);
$user->getRelations(); // return ['profile', 'settings', 'addresses'];
If I have more then 10 relation, I don't want to list all.
I would like to get like this:
$relations = ['profile', 'settings', 'addresses'];
Is this posible?
You could try adding a scope to the model, and so, you have to only write them once.
class User extends Model
{
public function profile() {
return $this->haOne(Profile::class);
}
public function settings() {
return $this->morphOne(Settings::class, 'settingsable');
}
public function addresses() {
return $this->hasMany(Addresses::class);
}
public function scopeWithRelations(Builder $query){
return $query->with([...]);
}
}
$users = User::withRelations()->get();
This way you only have to write them once there, and everywhere in the code you'll use the scope.
Not exactly 100% what you're asking, but this could be a solution.

How to set global variable laravel

I tried to make a global variable in laravel, in my code when the json return response, the data appears, but the other method is why it is null,
there is my code
class VendorController extends Controller
{
private $vendor_id;
public function index(){
if($cek =='available')
{
$this->vendor_id = DB::getPdo()->lastInsertId();
return response()->json([
'status' => 'success',
'vendor_id' => $this->vendor_id
]);
}
}
public function cek(){
dd($this->vendor_id)
}
}
when in function cek $this->vendor_id result is null, but in index function return->response()->json() there data is 13
Because that's different controller's instance. So you set the vendor_id in your index action, it will not display in show action,
Try to use session or redis to store the vendor_id:
Session:
public function index(){
...
$vendor_id = DB::getPdo()->lastInsertId();
$request->session()->put('vendor_id', $vendor_id);
...
}
public function show () {
$vendor_id = $request->session()->get('vendor_id'); // get your vendor_id
...
}
Redis:
PS: You need to install redis in your server.
use Illuminate\Support\Facades\Redis;
public function index(){
...
$vendor_id = DB::getPdo()->lastInsertId();
Redis::set('vendor_id', $vendor_id);
...
}
public function show () {
...
$vendor_id = Redis::get('vendor_id');
}
This is right way:-> Please Follow this
class VendorController extends Controller
{
private $vendor_id;
public function __construct(){
$this->vendor_id=DB::getPdo()->lastInsertId();
}
public function show(){
dd($this->vendor_id);
}
}

Resources