DELETE verb is not working in Yii Rest Api? - php

When try to delete a record using Yii Rest api
HTTP DELETE mothod is not working
my url routing is
array('users/list', 'pattern'=>'users/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'),
when i request like
http://localhost/api/users/delete?id=1
in method DELETE in rest client
it says there is no method like delete
so i created an action like the following
public function actionDelete()
{
switch($_GET['action'])
{
case 'delete': // {{{
$id = $_GET['id'];
$this->DeleteUser($id);
break; // }}}
default:
break;
}
}
Now it says undefined index : model
My understanding is if we use HTTP DELETE method we should have an action called actionDelete right?
How to fix this ?

verb => 'DELETE' means that the request method is delete.
You should be able to call your api with the following javascript:
$.ajax({
url: 'index.php/api/users/1',
type: 'DELETE',
async: false,
success: function(result) {
alert('Deleted');
},
error: function(result) {
alert('Could not delete!');
}
});
Do you have the standard filters active? If yes, you should remove "postOnly + delete".
/**
* #return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
'postOnly + delete', // we only allow deletion via POST request
);
}

Related

How to correctly throw an UnauthenticatedException in Cakephp 4?

I'm using the plugin Authentication 2 in cakephp 4.
I would like to throw an UnauthenticatedException when a user is not logged in and in the case of ajax request.
The goal is to catch the exception in JSON.
Here is my code from server :
// in src/Controller/Admin/AdminController.php
use Authentication\Authenticator\UnauthenticatedException;
class AdminController extends AppController {
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Authentication.Authentication');
}
public function beforeFilter(EventInterface $event)
{
parent::beforeFilter($event);
// The server receives an ajax request and the user is not logged in (any more), an UnauthenticatedException is thrown
if ($this->request->is('ajax') && $this->request->getAttribute('identity') === null) {
throw new UnauthenticatedException('Please log in');
}
}
}
Here is my code from client :
$.ajax({
dataType: 'json';
type: 'POST',
data: $(form).serialize(),
// [...]
})
// [...]
.fail(function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR.responseJSON); // There's no responseJSON in jqXHR...
alert("(" + errorThrown + ")" + jqXHR.responseJSON.message);
if (errorThrown == 'Unauthenticated') {
location.reload();
}
});
The problem is that there's no responseJSON in jqXHR.
Why is any other Exception (e.g UnauthorizedException that I used before) generating responseJSON in the return and not UnauthenticatedException ?
How to do to make it work with UnauthenticatedException ?
The authentication middleware by default re-throws unauthenticated exceptions, that is unless you configure the unauthenticatedRedirect option, in that case it will transform those exceptions into redirects accordingly.
If you need to support both HTML and JSON requests/responses, then you can for example dynamically configure, respectively not configure the unauthenticatedRedirect option, based on the current request, eg in your Application::getAuthenticationService() method do something along the lines of:
$service = new AuthenticationService();
$accepts = array_map('trim', explode(',', $request->getHeaderLine('Accept')));
$isJsonRequest = in_array('application/json', $accepts, true);
if (!$isJsonRequest) {
// service config for non-JSON requests
$service->setConfig([
'unauthenticatedRedirect' => /* ...*/,
'queryParam' => 'redirect',
]);
}
Alternatively to evaluating the header manually, require the request to be an instance of \Cake\Http\ServerRequest and use its is() method:
assert($request instanceof \Cake\Http\ServerRequest);
if (!$request->is('json')) {
$service->setConfig([
'unauthenticatedRedirect' => [/* ...*/],
'queryParam' => 'redirect',
]);
}
Also note that the authentication component will by default require the identity to be present and throw an exception accordingly, you do not have to do that yourself.

I want to pass array of IDs to route in Symfony

this is my controller:
/**
* #Route("/order", name="finish")
*/
public function createAction(Request $request)
{
$form = $this->createForm(OrderType::class);
// get data using the ids pass to the request...
// handle the form and redirect to homepage
return $this->render(
"orders/order_view.html.twig",
['order'=>$form->createView()]
);
}
I would like to pass some IDs to the request so i can get the needed data with doctrine.
After that handle the form create new order and add to it the products that i already have thanks to the ids passed.
i tried passing the ids using ajax on button click:
$.ajax(
{
type: 'POST',
url: '/order',
data: {'arr':[2,3,4]} // sample ids
}
).done(function (data) {
console.log(data)
}).fail(function () {
console.log("some error")
})
but it just returns the HTML. What i need is to render the form in the specified route ("/order") so i can handle it and insert into the database the new order with products added to it
I here answered to like this question:
Symfony2.8. How to get data from post request
You can use for POST request :
$request->request->get('data');
For GET request:
$request->query->get('data');
For FILE queries:
$request->files.

How do I call a function from Angular controller to Laravel Controller?

First off, I'm pretty new with Laravel+Angular which basically why I'm here.
I have this function delete from my Angular controller that uses $http.delete() to call the Laravel controller.
$scope.deleteJob = function(index) {
$scope.loading = true;
var job = $scope.jobs[index];
$http.delete('/api/job/' + job.jobId)
.success(function() {
$scope.job.splice(index, 1);
$scope.loading = false;
});;
};
With this route I should get to the Laravel controller:
Route::resource('api/job','ApiJobController');
Which i have defined a function to delete from my eloquent DB
public function destroy($id)
{
App\Job::destroy($id);
}
I don't know what I miss but everytime I invoke deleteJob(index) I get a Server Error.
DELETE http://localhost:8000/api/job/20 500 (Internal Server Error)
I tried using /api/job/destroy/, still getting 500
Try with this route
Route::get('/api/job','ApiJobController#destroy');
Or you can use
$http({
method: 'DELETE',
url: '/api/job/' + job.jobId
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Try this.
App\Job::find($id)->delete();

Laravel 5.2 return with errors - how to tell which form is submitted

I'm using Laravel 5.2. On my index page, I've got a button to add a new entry, which brings up the form in a lightbox. This form then submits via the create method.
I also have each entry listed on this page, with the ability to edit them inline, which submits via the update method.
I've setup validation via a Request. This means when someone misses something on the add, it redirects to the index method with errors. The errors only show though, when the lightbox is triggered by the user.
I know I can use $errors to see any errors, but I don't see how I can differentiate between the create and update forms for the sake of forcing the lightbox to appear on reload with create errors. Is there a way to do that?
Update:
Suggestion was made to use AJAX to bypass the reload issue, but now I'm getting a 422 return:
AJAX call:
(function(){
var submitAjaxRequest = function(e){
var form = $(this);
var method = form.find('input[name="_method"]').val() || 'POST';
$.ajax({
type: method,
url: form.prop('action'),
data: form.serialize(),
success: function(data){
console.log(data)
}
});
e.preventDefault();
}
$('form[data-remote]').on('submit', submitAjaxRequest);
})();
Request:
public function response(array $errors)
{
$response = parent::response($errors);
if ($this->ajax() || $this->wantsJson()) {
return $response;
}
return $response->with('requestMethod', $this->method());
}
I've also tested the ajax call and it works fine when the validation rules are met. It only fails if the validation comes back with something incorrect in the input.
You could override the response method so that you can flash the type of request.
In you Request class you could add
public function response(array $errors)
{
$response = parent::response($errors);
if ($this->ajax() || $this->wantsJson()) {
return $response;
}
return $response->with('requestMethod', $this->method());
}
(With ajax you wouldn't need to worry about the page reload so we can just return the original response.)
In the above I'm assuming you're using POST for your create methods and PUT or PATH for your update methods. If this is not the case you could use a way that make sense to you to differentiate between the requests.
Then in your view you could do something like:
#if(session('requestMethod') == 'POST')
https://laravel.com/docs/5.2/responses#redirecting-with-flashed-session-data
If you are going to use ajax, as I mentioned in the comment above, you will need to make sure you use the error method within the ajax call:
$.ajax({
type: method,
url: form.prop('action'),
data: form.serialize(),
success: function (data) {
console.log('success', data)
},
error: function (data) {
console.log('error', data)
}
});
Hope this helps!

How to call custom action in controller(laravel) using AngularJS

I am using laravel 5.
I have a custom action in my controller. By custom I mean it is not used by the resource object in angular. The following is the code of my controller.
class ServicesController extends Controller {
public function __construct()
{
$this->middleware('guest');
}
public function extras()
{
// code here
}
}
This is my service code in the angular script.
(function() {
'use strict';
angular
.module('bam')
.factory('myservice', myservice);
function myservice($resource) {
// ngResource call to the API for the users
var Serviceb = $resource('services', {}, {
update: {
method: 'PUT'
},
extras: {
method: 'GET',
action: 'extras'
}
});
function getExtras(){
return Serviceb.query().$promise.then(function(results) {
return results;
}, function(error) {
console.log(error);
});
}
}
})();
Now, the query() here will send the request to the index method in the laravel controller. How will I access the extras() action in the getExtras() method?
It looks like you're almost there try out the example below I tried to use what you have in your question, and added a few other custom endpoints as examples. You'll want a base URL set up similarly to the example so you can feed it an id out of your payload so $resource can set up your base CRUD. Otherwise to make custom routes using the same resource endpoint you can add some extra actions like you have in your question, but apply your customization on the base endpoints URL.
.factory('ServicesResource', ['$resource',
function ($resource) {
// Parameters used in URL if found in payload
var paramDefaults = {
id: '#id',
param: '#param'
}
// Additional RESTful endpoints above base CRUD already in $resource
var actions = {
custom1: {
method: 'GET',
url: '/api/services/custom',
},
custom2: {
method: 'GET',
url: '/api/services/custom/:param',
},
extras: {
method: 'GET',
url: '/api/services/extras'
}
update: {
method: 'PUT'
}
}
// Default URL for base CRUD endpoints like get, save, etc
return $resource('/api/services/:id', paramDefaults, actions);
}])
Now you can dependency inject the factory and use it like this:
var payload = {param:'someParam'};
ServicesResource.custom(payload).$promise.then(function(response){
// handle success
}, function(reason) {
// handle error
});
Or for Extras:
ServicesResource.extras().$promise.then(function(response){
// Handle success
}, function(reason) {
// Handle error
});
In Laravel you're route might be something like this:
Route::get('services/{param}/custom', 'ServicesController#custom');
Or for extras like this:
Route::get('services/extras', 'ServicesController#extras');
I got what I wanted using $http.
function getExtras(){
return $http.get('/services/extras').success(function (results) {
return results;
});
}
But, that would be nice if anyone suggest me how to do it with Serviceb.query().$promise.then.

Categories