Passing values from one controller to another - laravel-5

Been at this for ages, can't find a solution. I've searched and none of the posts help, possibly me not getting it as I'm new to Laravel (5.4)
I want to be able to be able to access $site_settings from one controller to another. Also $site_settings need to be accessible on all controllers and views. I also need to get variable from URL (hence Request in __construct( Request $request ) ) but it doesn't work either.
Would really appreciate any assistance.
Thanks.
See code below:
//BaseController
class BaseController extends Controller {
public function __construct( Request $request )
{
$slug = $request->slug;
$site_settings = \DB::table('sites_settings')->where('slug', $slug)->first();
View::share( 'site_settings', ['slug' => $slug, 'color' => $color] );
}
}
class SettingsController extends BaseController
{
// SettingsController
public function index( )
{
//how do I access $site_settings here and pass it on to the view?
// return view('settings.index');
}
}
---- UPDATE with Session ----
//BaseController
class BaseController extends Controller {
public function __construct()
{
$slug = Route::input('slug');
if(Session::get('slug') == $slug)
{
dd(Session::get('slug'));
}
else
{
$site_settings = \DB::table('sites_settings')->where('slug', $slug)->first();
Session::put('slug', $site_settings->slug);
}
}
}

Related

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

Does Laravel support "typed" requests?

To transform a database entity to an API response Laravel support resources, eg. UserResource extends JsonResource. The resource allows me to cleanly define which fields from the entity should be included in the response, how to transform them etc.
Is there a similar functionality for requests? My requests typically look like this:
public function create(JsonRequest $request): UserResource
{
$data = $request->json()->all();
/* Remove, transform, add request fields etc. */
$user = User::create($data);
$user->save();
return new UserResource($user);
}
In our case we have a legacy database behind a modern API so there are a number of fields that need to transformed, renamed etc. before pushing them into the entity class. The fields differ from request to request but the steps are very similar. Is there a less boilerplate-y way to do this, something similar to how resources transform entities to responses?
Something like:
class UserRequest extends JsonRequest {
public function fromArray(JsonRequest $request) {
…
}
}
Then the request could look like this:
public function create(UserRequest $request): UserResource
{
$user = User::create($request);
$user->save();
return new UserResource($user);
}
I suppose, that most of your problems can solve form request. See example below
Form request class:
namespace App\Http\Requests;
use Carbon\Carbon;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class TestRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'date' => 'required|date_format:Y-m-d H:i:s',
'name' => 'required|string',
];
}
// here you can specify custom error messages
public function messages()
{
return [
'date.required' => 'No date specified',
'date.date_format' => 'Invalid date format',
'name.required' => 'No name specified',
'name.string' => 'Invalid name format',
];
}
// here you can implement some data mapping before validation
protected function validationData()
{
return $this->transform($this->all());
}
// some data transformation logic
// You can place it anywhere in your applciation services
protected function transform($input)
{
$transformed = [];
foreach ($input as $field => $value) {
if ($field == 'name') {
$value = strtoupper($value);
} elseif ($field == 'date') {
$value = Carbon::parse($value)->toDateTimeString();
}
$transformed[$field] = $value;
}
return $transformed;
}
public function failedValidation(Validator $validator)
{
// here you can implement custom validation failure
parent::failedValidation($validator);
}
}
Here is my test route: Route::get('/test', 'TestController#index');
And controller:
use App\Http\Requests\TestRequest;
class TestController extends Controller
{
public function index(TestRequest $request)
{
return response()->json($request->validated());
}
}
So, then requesting route: curl -H 'Accept: application/json' 'http://localhost:8000/test?date=01.01.2019&name=petya'
And getting response: {"date":"2019-01-01 00:00:00","name":"PETYA"}
And dont be shy to see source code of request and form request, cause of not all methods you wish are described in docs. Hope this helps

Passing shared variable after login with Laravel 5.5

i created a method in order to share datas with all views of my application.
For this i created a class EntityRepository where i store the datas I want to share with all views.
Those data are displayed in the layout NOT the view.
class EntityRepository
{
use App\Valuechain;
public function getEntities()
{
$vcs = Valuechain::select('valuechains.id', 'lang_valuechain.vcname', 'lang_valuechain.vcshortname')
->join('lang_valuechain', 'valuechains.id', '=', 'lang_valuechain.valuechain_id')
->join('langs', 'lang_valuechain.lang_id', '=', 'langs.id')
->where('langs.isMainlanguage', '=', '1')
->whereNull('valuechains.deleted_at')
->get();
return $vcs;
}
}
When I want to send datas to the methods I simply call the getEntities() method... For example :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
// My code here ...
return view('admin.pages.maps.sectors.index', compact('entitiesLists', 'myVars'));
}
In this specific case it works fine and i don't have issue. My issue concerns the landing page after login.
In the loginController :
I defined the redirectTo variable this way :
public $redirectTo = '/admin/home';
For specific reasons I had to override the authentificated() method in the LoginController in order to check if my app is configured or need to be setup ...
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
//return redirect()->to('admin/home');
return redirect()->action('BackOffice\StatsController#index');
}
}
The concerned index() method is sending the variable onto the view :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
return view('admin.home', compact('entitiesLists'));
}
Whatever the return i make i have error message...
Undefined variable: entitiesLists (View: C:\wamp64\www\network-dev\resources\views\admin\partials\header-hor-menu.blade.php)
I finally solved this issue by changing my routes :
Route::group(['prefix' => 'admin'], function () {
Route::get('/', function (){
$checkAuth = Auth::guard('admin')->user();
if ($checkAuth) {
return redirect('/admin/main');
}
else {
return redirect('admin/login');
}
});
});
In my loginController i changed :
public $redirectTo = '/admin/home';
to :
public $redirectTo = '/admin/main';
Finally :
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
return redirect()->to('admin/main');
}
}

Laravel validation site belongs to user

My User.php
class User extends Authenticatable
{
public function sites()
{
return $this->hasMany(Site::class);
}
}
My Site.php
class Site extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
My routes.php
Route::resource('site', 'SiteController');
My SiteController.php
class SiteController extends Controller
{
public function edit(int $id)
{
$site = Auth::user()->sites()->find($id);
return view('site.edit', compact('site'));
}
}
How can I validate that the site belongs to user? I understand that in my case if site doesn't belong to user, $site variable will be null. But I want more declarative way, something like laravel requests, because I need the same check in show, update, and destroy methods. But I cannot use laravel request, because checking is something like this
$siteId = Route::current()->param('site');
$ids = Auth::user()->sites()->pluck('id')->toArray();
$result = in_array($siteId, $ids);
Can anyone suggest how to achieve my goal?
Since I use laravel 5.2, solution with route filters is deprecated. Instead route filter we should use middleware.
app/Http/Middleware/RestrictPermission.php
class RestrictPermission
{
public function handle($request, Closure $next)
{
$siteId = Route::current()->parameter('site');
if (!Auth::user()->sites()->find($siteId)) {
abort(403);
}
return $next($request);
}
}
app/Http/Kernel.php
class Kernel extends HttpKernel
{
protected $routeMiddleware = [
'restrict.permission' => RestrictPermission::class,
];
}
SiteController.php
class SiteController extends Controller
{
public function __construct()
{
$this->middleware('restrict.permission', ['except' => [
'index', 'create', 'store',
]]);
}
public function edit(int $id)
{
$site = Auth::user()->sites()->find($id);
return view('site.edit', compact('site'));
}
}

Routing zend request through a default controller when controller not found

Below is a function defined in my Bootstrap class. I must be missing something fundamental in the way Zend does routing and dispatching. What I am trying to accomplish is simple: For any request /foo/bar/* that is not dispatchable for any reason try /index/foo/bar/. The problem I'm having is when the FooController exists I get Action "foo" does not exist. Basically, the isDispatchable is always false.
public function run() {
$front = Zend_Controller_Front::getInstance();
$request = $front->getRequest();
$dispatcher = $front->getDispatcher();
//$controller = $dispatcher->getControllerClass($request);
if (!$dispatcher->isDispatchable($request)) {
$route = new Zend_Controller_Router_Route(
':action/*',
array('controller' => 'index')
);
$router = $front->getRouter();
$router->addRoute('FallBack', $route);
}
$front->dispatch();
}
So this seems to work, but is not the best answer as it simply drops all the params. I might try shortly doing a forward to /index/[original uri] within the plugin:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
protected function _initRoute() {
$front = Zend_Controller_Front::getInstance();
$routes = array(
'FallBack' => new Zend_Controller_Router_Route(
':controller/:action/*',
array('controller' => 'index', 'action' => 'index')
)
);
$router = $front->getRouter();
$router->removeDefaultRoutes();
$router->addRoutes($routes);
$front->setRouter($router);
return $router;
}
protected function _initPlugin() {
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new My_Controller_Plugin_FallBack());
}
}
class My_Controller_Plugin_FallBack extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$front = Zend_Controller_Front::getInstance();
$dispatcher = $front->getDispatcher();
$router = $front->getRouter();
if (($router->getCurrentRouteName() == 'FallBack') &&
!$dispatcher->isDispatchable($request)) {
$request->setActionName($request->getControllerName());
$request->setControllerName('index');
}
}
}
if i understand your idea right
would you try to use __call magic method ??
then use $this->_redirect(); to your default action for example
more info are here http://php.net/manual/en/language.oop5.overloading.php
UPDATE
if you opened Zend/Controller/Action.php on line 480
public function __call($methodName, $args)
{
require_once 'Zend/Controller/Action/Exception.php';
if ('Action' == substr($methodName, -6)) {
$action = substr($methodName, 0, strlen($methodName) - 6);
throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404);
}
throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500);
}
what i meant to do is to extend this class and override __call function exactly to be
classs My_Controller_Action extends Zend_Controller_Action{
public function __call($methodName, $args)
{
///// do your magic here ......redirection or logging the request or what ever
}
}
and make sure your controller extend your newly created class
class FooController extends My_Controller_Action
{
public function indexAction()
{
// action body
}
}
so if some how you called inexistent action __call will run
this idea was about inexistent action only
it won't work if the controller doesn't exist

Resources