Problems with destroy() Method in Laravel Backpack - laravel

I'm having problems overriding the destroy() method in Laravel Backpack. When I try to do more, like calling an external method using cURL to an API inside the destroy() method of my entityCRUD, it stops working (and there are no errors returned).
<?php
public function destroy($id)
{
$this->crud->hasAccessOrFail('delete');
$customer = Customer::find($id);
$array_api_user_options = AdminUserJsonRepositoryData::deleteArrayData();
$array_api_user_options['mail'] = $customer->email;
$array_api_user_options['ke'] = $customer->api_group_key;
$array_api_user_options['uid'] = $customer->api_user_id;
// Instancia o Shinobi com token e group key
$apiShinobi = New ShinobiAPIRepositoryAPI($customer->api_auth_token, $customer->group_key, $customer->user_id);
$apiShinobi->deleteAdminUser(json_encode($array_api_user_options));
return $this->crud->delete($id);
}
When I remove the line: $apiShinobi->deleteAdminUser() it works again and deletes my record. Can someone help me out, please?

If it work without that line, the problem is definitely with that line :-)
In Chrome Developer Tools, the Network tab, you should be able to see the result of your AJAX request - and the error you're getting:

Related

Mocking a controller enters controller instead of mock

The bounty expires in 5 days. Answers to this question are eligible for a +50 reputation bounty.
Chris Rockwell wants to draw more attention to this question.
I am trying to get comfortable with tests in Laravel and playing around with Dusk.
Given I have the following controller:
class CoursesController extends Controller {
private ApiServiceProvider $api;
public function __construct(ApiServiceProvider $apiServiceProvider) {
$this->api = $apiServiceProvider;
}
public function getCoursesCache(array $cIds = []) : array {
// Breakpoint here - always gets hit when running tests
if (empty($cIds)) {
$cIds = Request::capture()->query('cIds');
$cIds = explode(',', $cIds);
}
return $this->api->getCoursesCache($cIds);
}
}
Which is used by a route:
Route::get('/api/v1/courses/cache', 'App\Http\Controllers\Api\CoursesController#getCoursesCache')->name('courses.cache');
This route is used internally by a VueJS component, which is ultimately what I'd like to test.
I am using Dusk to do some browser based testing and I want to mock the controller response for getCoursesCache. However, when I use the following (with a breakpoint in the controller method) I always enter the controller instead of just returning the mock.
$courseController = $this->mock(CoursesController::class)->makePartial();
$item = new CourseCacheItem();
$item->name = $course->name;
$courseController->shouldReceive('getCoursesCache')
->with([$course->getKey()])
->andReturn([$item]);
$this->browse(function (Browser $browser) use ($course) {
$browser->visit('/')
->waitFor('.course-card-container--data-loaded', 10)
->screenshot('filename')
->assertSee($course->name);
});
I've also tried this to create the mock:
$cc = $this->createMock(CoursesController::class);
$item = new CourseCacheItem();
$item->name = $course->name;
$cc->expects($this->once())->method('getCoursesCache')->with([$course->getKey()])->willReturn([$item]);
Edit: I've also now tried Mocking and Spying on the injected service ApiServiceProvider but the code enters that real class during the test run as well.
My expectation is that my breakpoint within the actual CoursesController would never be hit - what am I doing wrong?
Your issue here is that you are dealing with two separate Laravel Runtime.
You can check this issue for more infos.
Basically, when you are making a Dusk test with an Http call, Dusk will make a real Http call to a fresh Laravel instance/runtime (using Chrome Headless).
So you end up having one runtime where you are lunching the test, and the second one where dusk is making an http call.
The second Laravel instance is not running your Mock and doesnt know about it. That's why you end up in the actual Controller.
One solution i found in the past is making a route responsible to mock what i need.
This route should be called in the the html page before the assertion is happening.
So when you make a Dusk http call some Js (in the second Laravel instance) will call the route and the mock will be setup.
Fortunately for you there is great package that can handle this for you. https://github.com/NoelDeMartin/laravel-dusk-mocking

Laravel Nova - Observer Update Method Causes 502

When trying to update a resource in Laravel Nova that has a Observer the update loads for a while and then ends with a 502 error. The observer is registered correctly (the created method works fine) and I'm not trying to do anything special in the updated method. Any ideas?
public function updated(Model $model)
{
//
$model->title = 'test';
$model->save();
}
If I try this without the $model->save(), there is no 502 error but the change I want to happen also doesn't happen. I get the green success message, and any change I make on the form prior to updating occurs, but not the change I'm trying to make during the updated method.
Any help troubleshooting this would be appreciated
I am not very good at Laravel, but I think, that you should to try this:
In your model file add method:
public function saveQuietly(array $options = [])
{
return static::withoutEvents(function () use ($options) {
return $this->save($options);
});
}
Then, in your updated method in observer do something like this:
public function updated(Model $model)
{
$model->title = 'test';
$model->saveQuietly();
}

Laravel 5.2 - How to access an App Presenter method in EventServiceProvider?

I have a guitar lessons site where there is an exercises table. The original developers placed some functions in ExercisePresenter to retrieve other bits of data associated with an exercise, such as its url.
Here is a function in ExercisePresenter that returns url for an exercise:
public function url()
{
return '/guitar-lesson-ex/' . $this->urlName() . '/' . $this->id;
}
So now I am creating an event on new exercise created so I can use pusher notifications. In the EventServiceProvider I have this:
public function boot(DispatcherContract $events)
{
parent::boot($events);
Exercise::created(function ($exercise) {
// need to update lesson difficulty
$lesid = $exercise->lesson_id;
$les = \App\Lesson::find($lesid);
$dif = $les->difficulty();
DB::table('lessons')
->where('id', $lesid)
->update(['difficulty' => $dif]);
// lets trigger NewExerciseEvent to send pusher notifications
$url = $exercise->url;
event(new NewExerciseEvent($message));
});
}
I thought in above code $url = $exercise->url; would work since I see $exercise->url used successfully in exercise views. But it is returning $url as null. Now, there is no url column in the exercise database, so I figure somehow when $exercise->url; is used in a view, laravel is figuring out that the ExercisePresenter is able to return the url.
I am debugging through PHPStorm, but when I get to $url = $exercise->url; and step in, I am just taken through various bits of laravel code that looks for a method, etc. I am not savvy enough with laravel to figure out what it is doing here differently than in the view (too bad we can't debug views...), but each time I try this $url is returned as null.
Any idea how to get this to work properly in my EventServiceProvider?
Thanks!
Figured it out:
$url = $exercise->present()->url;
I had been searching for how to use presenters but having just read (Laravel View Presenters From Scratch), everything is clear!
Sorry for posting prematurely.

Laravel 4: redirect if item doesn't exists, ModelNotFoundException doesn't work anyway I try it

I'm following Dayle Rees' book "Code Bright" tutorial on building a basic app with Laravel (Playstation Game Collection).
So far so good, the app is working but, following his advices at the end of the chapter, I'm doing my homeworks trying to improve it
So, this snippet is working fine for existing models but throws an error if the item doesn't exists:
public function edit(Game $game){
return View::make('/games/edit', compact('game'));
}
In other words, http://laravel/games/edit/1 shows the item with ID = 1, but http://laravel/games/edit/21456 throws an error since there's no item with that ID
Let's improve this behaviour, adapting some scripts found also here on StackOverflow (Laravel 4: using controller to redirect page if post does not exist - tried but failed so far):
use Illuminate\Database\Eloquent\ModelNotFoundException; // top of the page
...
public function edit(Game $game){
try {
$current = Game::findOrFail($game->id);
return View::make('/games/edit', compact('game'));
} catch(ModelNotFoundException $e) {
return Redirect::action('GamesController#index');
}
}
Well... nothing happens! I still have the error with no redirect to the action 'GamesController#index'... and please notice that I have no namespaces in my Controller
I tried almost anything:
Replace catch(ModelNotFoundException $e) with catch(Illuminate\Database\Eloquent\ModelNotFoundException $e): no way
put use Illuminate\Database\Eloquent\ModelNotFoundException; in Model instead of Controller
Return a simple return 'fail'; instead of return Redirect::action('GamesController#index'); to see if the problem lies there
Put almost everywhere this snippet suggested in Laravel documentation
App::error(function(ModelNotFoundException $e)
{
return Response::make('Not Found', 404);
});
Well, simply nothing happened: my error is still there
Wanna see it? Here are the first two items in the errors stack:
http://www.iwstudio.it/laravelerrors/01.png
http://www.iwstudio.it/laravelerrors/02.png
Please, can someone tell me what am I missing? This is driving me mad...
Thanks in advance!
Here are few of my solutions:
First Solution
The most straightforward fix to your problem will be to use ->find() instead of ->findOrFail().
public function edit(Game $game){
// Using find will return NULL if not found instead of throwing exception
$current = Game::find($game->id);
// If NOT NULL, show view, ELSE Redirect away
return $current ? View::make('/games/edit', compact('game')) : Redirect::action('GamesController#index');
}
Second solution
As I notice you may have been using model binding to your route, according to Laravel Route model binding:
Note: If a matching model instance is not found in the database, a 404 error will be thrown.
So somewhere where you define the model binding, you can add your closure to handle the error:
Route::model('game', 'Game', function()
{
return Redirect::action('GamesController#index');
});
Third Solution
In your screenshot, your App::error seems to work as the error says HttpNotFound Exception which is Laravel's way of saying 404 error. So the last solution is to write your redirect there, though this apply globally (so highly discouraged).

symfony2 crud & http cache

I'm using Symfony2 and I have a ReaderBundle that has an Rss entity.
I'm created CRUD for this entity.
php app/console generate:doctrine:crud --entity=RSSReaderBundle:Rss --format=annotation --with-write
All was well, before I connected Cache.
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppCache.php';
require_once __DIR__.'/../app/AppKernel.php';
Debug::enable();
$kernel = new AppKernel('dev' , true);
$kernel->loadClassCache();
$kernel = new AppCache($kernel); // THAT STRING IS MAIN PROBLEM
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
And then when i'm trying to delete some record, i take this error:
No route found for "POST /rss/delete/30": Method Not Allowed (Allow: DELETE)
405 Method Not Allowed
I created a form that clearly indicates the method:
private function createDeleteForm($id)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('rss_delete', array('id' => $id)))
->setMethod("DELETE")
->add('submit', 'submit', array('label' => 'Delete'))
->getForm()
;
}
I have not found the problem. Help please
This problem occurred since symfony2.2, see https://github.com/symfony/symfony-standard/commit/1970b831f8843a5cf551e9d88404cb62f21b90f9
You need to modify the Symfony\Component\HttpFoundation\Request::$httpMethodParameterOverride boolean manually in your app.php file:
// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
Request::enableHttpMethodParameterOverride();
There is no method="DELETE" in html forms ... at least not supported in almost all browsers - only in ajax requests.
Work around this by allowing DELETE and POST requests to the route.
we must remove the string with comment "THAT STRING IS MAIN PROBLEM". Cache is working all the same. And CRUD working right
I have the same problem that you had (with PUT and DELETE HTTP method) but I don't understand your solution.
Did you:
a) just get rid of // THAT STRING IS MAIN PROBLEM
or
b) get rid of $kernel = new AppCache($kernel); // THAT STRING IS MAIN PROBLEM
The solution b) is the same as not using cache so in my case, it's not helping as the page take a very long time to load.
#Nifr:
I thought there were method PUT and DELETE. I use them in my forms following the instructions on this link: http://symfony.com/fr/doc/current/cookbook/routing/method_parameters.html
So in fact, Symfony2 is able to tell whether a method is PUT, DELETE, POST or GET. But somehow, the cache can't...
Any help on that?
Edit:
I found a solution that doesn't involve changing anything in the app.php file.
Basically, the problem comes from the fact that the getMethod method of the request object of symfony2 doesn't know about PUT or DELETE method. The point is to change that in the AppCache.php file.
We just have to override the method invalidate of the AppCache.php file:
protected function invalidate(Request $request, $catch = false)
{
$request->setMethod($request->request->get('_method'));
return parent::invalidate($request, $catch);
}
Here, I just change the method of the request by the method posted from the form.

Resources