Laravel Model Controller Dependency injection - laravel

I have the following problem. I hope my approach is not completely wrong, feel free to advice.
I have a Model class Chat.php
protected $skip;
protected $take;
protected $agreements;
protected $chat;
public function getSkip()
{
return $this->skip;
}
public function setSkip($skip)
{
$this->skip = $skip;
}
public function getTake()
{
return $this->take;
}
public function setTake($take)
{
$this->take = $take;
}
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->setTake(8);
$this->setSkip(8);
}
I set properties skip and take here.
Then, I have the DashboardController
class DashboardController extends Controller
{
private $chat;
/**
* DashboardController constructor.
* #param $chat
*/
public function __construct(Chat $chat)
{
$this->chat = $chat;
}
/**
* Display a listing of the authenticated resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$chats = Chat::orderBy('created_at','desc')->skip($this->chat->getSkip())->take($this->chat->getTake())->get();
$agreements = AgrType::orderBy('created_at','desc')->take(10)->get();
return view('sections.dashboard', compact('chats','agreements'));
}
public function loadMore()
{
$this->chat->setSkip($this->chat->getSkip() - 1 );
$this->chat->setTake($this->chat->getTake() - 1);
return redirect('/dashboard');
}
My approach is as follows:
After a user clicks on button, route /loadmore get him to this controller and triggers loadMore function.
LoadMore function then gets values through accessors and sets values with mutator.
Index method then simply reads this values.
So the meaning is: I show chat window (rather maybe comments window cause this si not really a chat), index method is called.
Index method reads the values and displays comments according to query. -> this one is OK
Now, what does NOT work:
When I click button, loadMore function gets called, sets the values which index method then reads and reloads according to them.
What did I try: I tried loadMore method to display its own values (changed) and return them, but then I have a new route for reloaded chat and it is not what I want.
What do I miss? Is my approach OK? (I know javascript is maybe better for this, but I want a Laravel way, get and post.)
Thanks in advance.

Your controller functions get executed within in completely separate requests.
All return redirect('/dashboard'); does in loadMore() send your browser to the dashboard route. Your browser then makes a new request to index() on which your controller gets instantiated again, its __construct() function run again and a new empty Chat model gets instantiated.
I recommend you put the take and skip parameters into your url like this:
$router->get('/dashboard/{skip}/{take}', 'DashboardController#index');
And change your index() function to this:
public function index($skip, $take)
That way it will work, however the even better way of doing it would be to use Laravel's paginate() function: https://laravel.com/docs/5.6/pagination
public function index()
{
$chats = Chat::orderBy('created_at','desc')->paginate();
$agreements = AgrType::orderBy('created_at','desc')->take(10)->get();
return view('sections.dashboard', compact('chats','agreements'));
}

Related

Laravel authorization policy not working on Show page

I have a laravel app using Policies to assign roles and permissions, i cant seem to access the show page and im not sure what im doing wrong?
If i set return true it still shows a 403 error as well, so im unsure where im going wrong here. The index page is accessable but the show page is not?
UserPolicy
public function viewAny(User $user)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
public function view(User $user, User $model)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
UserController
public function __construct()
{
$this->authorizeResource(User::class, 'user');
}
public function index()
{
$page_title = 'Users';
$page_description = 'User Profiles';
$users = User::all();
return view('pages.users.users.index', compact('page_title', 'page_description', 'users'));
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
$user = User::findOrFail($id);
$user_roles = $user->getRoleNames()->toArray();
return view('pages.users.users.show', compact('user', 'user_roles'));
}
Base on Authorize Resource and Resource Controller documentation.
You should run php artisan make:policy UserPolicy --model=User. This allows the policy to navigate within the model.
When you use the authorizeResource() function you should implement your condition in the middleware like:
// For Index
Route::get('/users', [UserController::class, 'index'])->middleware('can:viewAny,user');
// For View
Route::get('/users/{user}', [UserController::class, 'view'])->middleware('can:view,user');
or you can also use one policy for both view and index on your controller.
I had an issue with authorizeResource function.
I stuck on failed auth policy error:
This action is unauthorized.
The problem was that I named controller resource/request param with different name than its model class name.
F. ex. my model class name is Acknowledge , but I named param as timelineAcknowledge
Laravel writes in its documentation that
The authorizeResource method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument
So the second argument had to be request parameter name.
// Here request param name is timelineAcknowledge
public function show(Acknowledge $timelineAcknowledge)
{
return $timelineAcknowledge->toArray();
}
// So I used this naming here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'timelineAcknowledge');
}
Solution was to name request param to the same name as its model class name.
Fixed code example
// I changed param name to the same as its model name
public function show(Acknowledge $acknowledge)
{
return $acknowledge->toArray();
}
// Changed here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'acknowledge');
}
I looked over Laravel policy auth code and I saw that the code actually expects the name to be as the model class name, but I couldn't find it anywhere mentioned in Laravel docs.
Of course in most of the cases request param name is the same as model class name, but I had a different case.
Hope it might help for someone.

Laravel, having a custom controller method with custom policy method?

I have a resource controller and want to add an extra custom policy method for destroyMany
In which I would check if the user is admin before deleting many.
The default methods work fine
Controller Method
Policy Method
index
viewAny
show
view
create
create
store
create
edit
update
update
update
destroy
delete
destroyMany
destroyMany
Controller destroyMany method is called, the policy isn't
Or should I stick to Gates for this extra method?
The docs say I can have any name for the methods and policies, How can both be linked?
destroyMany->destroyMany or
destroyMany->deleteMany would be a good setup.
And would be a great addition to my resource controller (where it should reside)
class ResourceController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
$this->authorizeResource(Resource::class, 'resource');
}
public function index()
{
return ResourceCollection::collection(Resource::all());
}
public function destroyMany(Request $request)
{
// gets called but needs a policy which isn't called
}
}
policy
class ResourcePolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
public function viewAny(User $user)
{
// works
return $user->hasAnyRoles(['admin', 'superAdmin']);
}
public function delete(User $user, Resource $resource)
{
// works
return $user->hasAnyRoles(['admin', 'superAdmin']);
}
public function deleteMany(User $user, Resource $resource)
{
// not called because the controller method needs to be hooked up, like the other methods
}
}
To get the addition policy method to work you will need to update the resourceAbilityMap for the controller. Adding the following to your controller should do the trick:
protected function resourceAbilityMap()
{
return array_merge(parent::resourceAbilityMap(), [
'destroyMany' => 'deleteMany'
]);
}
Also, if you don't return anything from your deleteMany policy method it will result in a 403.
If you're route/controller method isn't receiving an instance of the model then you will also need to update the array returned from the resourceMethodsWithoutModels method:
protected function resourceMethodsWithoutModels()
{
return array_merge(parent::resourceMethodsWithoutModels(), ['destroyMany']);
}

Please how do I share data from show method to two different views

Please I need to know if there is a way I can share data from one controller method to multiple views,
This is the CategoryController show method
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$category = Category::find($id);
$users = $category->user;
return view('categories.show')->with('users', $users);
}
what I want is to share the same data with another page profile-display.blade.php without creating another controller.
#Adam this will help you.
route.php
Route::get('users/{id}', 'CategoryController#show')->name('profile');
Route::get('Category/{id}', 'CategoryController#show')->name('category');
CategoryController.php
public
function show($request, $id) {
$category = Category::find($id);
$users = $category->user;
if ($request::route()->getName() == 'category') {
return view('categories.show')->with('users', $users);
} else {
return view('profile.show')->with('users', $users);
}
}
Different routes can use the same controller, but you are going to have a harder time having a single controller present multiple views without a chaos of conditions or at least just make a new controller/method.
You can shave of some of your of your code to make a slimmer approach, though, by using model binding with routes:
routes.php
Route::get('categories/{category}', 'CategoryController#show');
and then in CategoryController.php:
public function show(Category $category)
{
return view('categories.show')->with('users', $category->user);
}
This will enable model binding to auto-instantiate the model if it exists and return a 404 if not.
You can reiterate the process for a second view, but just reuse the same controller (which I personally wouldn't prefer at all). Just add the route and the new method in the same controller:
routes.php
Route::get('categories/{category}', 'CategoryController#show');
Route::get('profile-display', 'CategoryController#profileDisplay');
and then in CategoryController.php:
public function show(Category $category)
{
return view('categories.show')->with('users', $category->user);
}
public function profileDisplay()
{
return view('profile-display');
}
I haven't added any model bindings to the profileDisplaymethod as I couldn't really understand how you would like to attache the category to a profile display page (as the name suggests), but that could give you some rough ideas.
you can use \Illuminate\Support\Facades\View::share('foo', 'bar');

Pass variable from one method to another in same controller Laravel

I need to pass select option value from store method to show
i need to pass the $typeg value to show method
public function store(Request $request ) {
$typeg = $request->input('type');
}
public function show($id) {
dd($this->store($typeg));
}
i get
Undefined variable:
or
Too few arguments to function app\Http\Controllers\appController::show(), 1 passed and exactly 2 expected
Try this
on the first function you have some variable witch you want to pass it to another function\method
Than you need to use $this and the name of the other method you'd like to pass the var too something like this.
public function oneFunction(){
$variable = "this is pretty basic stuff in any language";
$this->anotherFunction($variable)
}
public function anotherFunction($variable){
dd($variable);
}
Store your data on session (or somewhere else like cookie, cache, database). So you can reach the data later.
class SomeController extends Controller {
public function store(Request $request ) {
session(["typeg"=>$request->input('type')])
}
public function show($id) {
dd(session("typeg"));
}

Call method from (custom) controller class in Magento

I'm working with the M2e extension for Magento. Now I want to call a method of the class Ess_M2ePro_Adminhtml_ListingController in the file app/code/community/Ess/M2ePro/controllers/Adminhtml/ListingController.php.
But I don't know, how. I can't create an object or model to get access to the class to use the methods. Maybe it's not a good idea to call this controller methods directly, but in my case (remove a associated magento product to an ebay listing) it's required to call this methods.
In general these actions are called from the magento backend. I've also tried to create an admin_html session, but at the moment I don't have any further ideas.
Here's an example, how it looks like. I'm working with regular PHP-code, nothing special:
class Ess_M2ePro_Adminhtml_ListingController extends Ess_M2ePro_Controller_Adminhtml_MainController
{
//#############################################
protected function _initAction()
{
/** removed **/
}
protected function _isAllowed()
{
return Mage::getSingleton('admin/session')->isAllowed('m2epro/listings/listing');
}
//#############################################
public function indexAction()
{
/** removed **/
}
//#############################################
public function searchAction()
{
/** removed **/
}
public function searchGridAction()
{
/** removed **/
}
public function lockListingNowAction()
{
$listingId = (int)$this->getRequest()->getParam('id');
$component = $this->getRequest()->getParam('component');
$lockItemParams = array(
'id' => $listingId,
'component' => $component
);
$lockItem = Mage::getModel('M2ePro/Listing_LockItem',$lockItemParams);
if (!$lockItem->isExist()) {
$lockItem->create();
}
exit();
}
}
And I'm looking for something like this:
$test = Mage::getModel('M2ePro/Ess_M2ePro_Adminhtml_ListingController')->lockListingNowAction();
You shouldn't call methods from an other controller. Specially in your case, when you have exit at the end of the method.
You can use the _forward method if you are in a controller:
$this->_forward($action = 'lockListingNowAction', $controller = 'adminhtml_listing', $module = 'M2ePro', $params = array('id'=>$id)) //controller name may be different
But the cleanest way is to have the code you need in a helper and call the code from that helper in both controllers.

Resources