The view 'Route' was not found, but it actually exist in nopcommerce 4.5.2 - model-view-controller

Appears:
An unhandled exception occurred while processing the request.
InvalidOperationException: The view '/OGS/Route.cshtml' was not found. The following locations were searched: /OGS/Route.cshtml
Although the file is present on the first path:
Nop.Web => Areas => Admin => Views => OGS => Route.cshtml
Here is the controller code,
public class OGSRoute : BaseAdminController
{
public virtual async Task<IActionResult> Index()
{
return View("/OGS/Route.cshtml");
}
}

Please try this viewName: Areas/Admin/Views/OGS/Route.cshtml
public virtual async Task<IActionResult> Index()
{
return View("Areas/Admin/Views/OGS/Route.cshtml");
}

Change like below
public partial class OGSRouteController : BaseAdminController
{
public virtual async Task<IActionResult> Index()
{
return View("Areas/Admin/Views/OGS/Route.cshtml");
}
}

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

Laravel: prevent changing other users' items

I have three models. I want to avoid that users can change the todo's from todolists belonging to other users.
class User extends Authenticatable
{
public function todolists()
{
return $this->hasMany('App\Todolist');
}
public function todos()
{
return $this->hasManyThrough('App\Todo', 'App\Todolist');
}
}
class Todolist extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
public function todos()
{
return $this->hasMany('App\Todo');
}
}
class Todo extends Model
{
protected $casts = [
'completed' => 'boolean',
];
public function todolist()
{
return $this->belongsTo('App\Todolist');
}
}
To avoid users can view other users' todolists and todo items, I have implemented the following:
public function getTodosForTodolist(Todolist $todolist)
{
if (Auth::user()->id == $todolist->user_id) {
$todos = Todo::where('todolist_id', $todolist->id )->get();
return view('todo/index', ['todos' => $todos);
}
else {
abort(403, 'Unauthorized action.');
}
}
Next step is to prevent that users can edit other users' todo items. Currently in the TodoController I have simply the following:
public function edit(Todo $todo)
{
if (Auth::user()->todos->id == $todo->todolist->id) {
return view('todo/edit', ['todo' => $todo]);
}
}
This gives the following error:
Property [id] does not exist on this collection instance.
The error is because the current user has multiple todos. So I changed my code as follows.
public function edit(Todo $todo)
{
if (Auth::user()->todos->first()->id == $todo->todolist->id) {
return view('todo/edit', ['todo' => $todo]);
}
abort('403', 'Unauthorized action.');
}
This works but it just feels very wrong to do this as such.
What would be a better way to accomplish that users' can view/edit/delete items belonging to other users?
I suggest that you use policies for your Todo and TodoList models and a scope to restrict todos to one user to prevent duplicated code within your app:
class ToDoListPolicy
{
public function view(User $user, TodoList $post)
{
return $user->id === $todolist->user_id;
}
}
class ToDoPolicy
{
public function edit(User $user, Todo $toDo)
{
$toDo->loadMissing('todolist');
return $user->id === $toDo->todolist->user_id;
}
}
Register them in your AuthServiceProvider.php
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
TodoList::class => ToDoListPolicy::class,
Todo::class => ToDoPolicy::class
];
}
and then use them in your actions:
public function getTodosForTodolist(Todolist $toDoList)
{
$this->authorize('view', $toDoList);
$toDoList->loadMissing('todos');
return view('todo.index', ['todos' => $toDoList->todos);
}
class ToDoController extends Controller
{
public function edit(Todo $toDo)
{
$this->authorize('edit', $toDo);
return view('todo.edit', compact('toDo'));
}
}
And a scope to restrict the query to a specific user:
class Todo extends Model {
// ...
public function scopeByUser(Builder $query, ?User $user = null)
{
if (! $user) {
$user = Auth::user();
}
$query->whereHas('todolist', function (Builder $toDoListQuery) use ($user) {
$toDoListQuery->where('user_id', $user->id);
});
}
}
Answer to your questions in the comments.
Q1: I had to put Auth::user()->can('view', $todolist); in an if-else clause for it to work. Guess this is the way it works?
Q2: what is the difference between $this->authorize('edit', $todo) and Auth::user()->can('edit', $todo)?
Sorry, that was a mistake on my side. Auth::user()->can() returns a boolean whereas $this->authorize() (which is a method of the AuthorizesRequests trait usually included in the BaseController) throws an exception if the authorization failed.
If you want to let each user work only with his/her own Todos then adding a Global Scope is what you are looking for. This implementation will let your application feel that Todos ( of users other than the logged one ) does not exist.
Global Scopes can be used for many models which means it will reduce boiler plate code.
https://laravel.com/docs/7.x/eloquent#global-scopes

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);
}
}

On sorting and filtering showing "An error occured, please try again later" in magento

when I am clicking on any sort or filter option in category page it is showing an error occurred please try again please help.
<?php
class MageTracking_TicketSystem_Block_Ticketsystem_View extends Mage_Core_Block_Template
{
protected function _prepareLayout(){
$this->getLayout()->getBlock('head')->setTitle(Mage::helper('ticketsystem')->__('Ticket'));
return parent::_prepareLayout();
}
public function getTickets(){
return Mage::registry('ticketsystem_all');
}
public function getDepartments(){
return Mage::helper('ticketsystem')->getAllCategories(false);
}
public function getDepartment($id){
return Mage::helper('ticketsystem')->getCategory($id);
}
public function getPriority($priority){
$priorites= Mage::helper('ticketsystem')->getPriorities();
return $priorites[$priority];
}
public function getStatus($status){
$statuses = Mage::getSingleton('ticketsystem/status')->getOptionArray();
return $statuses[$status];
}
}
If I am not wrong you are using Tracking Ticketing System extension in your site.
Go to line number 35 in following file app\code\community\MageTracking\TicketSystem\Block\Ticketsystem\View.php
class MageTracking_TicketSystem_Block_Ticketsystem_View extends Mage_Core_Block_Template
{
protected function _prepareLayout(){
$this->getLayout()->getBlock('head')->setTitle(Mage::helper('ticketsystem')->__('Ticket'));
return parent::_prepareLayout();
}
Following line is creating the problem
$this->getLayout()->getBlock('head')->setTitle(Mage::helper('ticketsystem')->__('Ticket'));
You can check the error message in your browser console also.

Laravel MVC concept

I am still used to MVC concept but i understand the basic concept of it.
I found this code on a "PHP" blog.
<?php
class Todo_Controller extends Base_Controller
{
public function action_list() {
$todos = Todo::all();
return View::make("list")
->with("todos", $todos);
}
public function action_view($id) {
$todo = Todo::where_id($id)->first();
return View::make("view")
->with("todo", $todo);
}
public function action_delete($id) {
$todo = Todo::where_id($id)->first();
$todo->delete();
return View::make("deleted");
}
public function action_new() {
return View::make("add");
}
public function action_add() {
$todo = new Todo();
$todo->title = Input::get("title");
$todo->description = Input::get("description");
$todo->save();
return View::make("success");
}
}
That is a controller but I notice action_list(), action_view() and action_delete() are running SQL but it is doing it in a controller.
Why is that? shouldn't that be in the model? Isn't the purpose of a model to do anything data related?
The reason why I am asking this is because I have seen a lot of laravel tutorials both paid and unpaid ones doing this and I am asking myself, why mix the business logic with the data schema?
You can use the repository pattern to extract the data querying from your controller.
class TodoRepository {
public function get_todo($id)
{
return Todo::find($id);
}
public function get_all_todos()
{
return Todo:all();
}
public function create_todo($todo)
{
return Todo::create([
'title' => $todo['title'],
'description' => $todo['description']
]);
}
public function delete_todo($todo)
{
return Todo::find($todo)->delete();
}
}
Then you inject the repository into your controller. That way if you change databases, or ditch eloquent then you just write a new repository with the same interface and you simply change out the injection.
class Todo_Controller extends Base_Controller
{
private $todos;
public function __construct(TodoRepository $todos)
{
$this->todos = $todos;
}
public function action_list() {
return View::make("list")
->with("todos", $this->todos->get_all_todos());
}
public function action_view($id) {
return View::make("view")
->with("todo", $this->todos->get_todo($id));
}
public function action_delete($id) {
$this->todos->delete_todo($id);
return View::make("deleted");
}
public function action_new() {
return View::make("add");
}
public function action_add() {
$todo = $this->todos->create_todo(Input->get('title', 'description');
return View::make("success");
}
}
This was your controller doesn't care how you get_all_todos or delete_todo, it simply asks the repository to get/modify the data then it returns the result.

Resources