Retrieve data sent by xmlhttprequest in cakephp's controller - cakephp

I want to send some data (image,text,...) to Posts controller :
$('#home').click(function (){
var xhr = new XMLHttpRequest();
xhr.open("POST","/Portfilo/posts/test",true);
xhr.send("id=10");
xhr.onreadystatechange=function()
{
if (xhr.readyState==4 && xhr.status==200)
{
alert(xhr.responseText);
}
}
});
test action is :
public function test()
{
$this->layout = 'ajax';
//$id = $this->params['named']['id'];
if($this->request->named){
echo "Yesssssss";
}
else {
echo 'Oh No';
}
}
how I cane retrieve these data from this connection (xmlhttprequest).
I read this article but functions or properties like these :
// Passed arguments
$this->request->pass;
$this->request['pass'];
$this->request->params['pass'];
Or
// named parameters
$this->request->named;
return to me "Oh Noooo" message.
How to retrieve these parameter and data s from this request?

If you are sending data through POST method to the test action, you can retrieve it using $this->request->data array, which will contain all variables sent by POST.
In your case, you can try this:
public function test(){
$this->layout = 'ajax';
if($this->request->data['id']){
echo "Yesssssss";
}
else {
echo 'Oh No';
}
}

Related

PUT request with formData could not update using react.js and laravel

I am not receiving formdata in the Api endpoint which is being sent by fetch and PUT method.
I used the POST method and it worked out which i think is not recommended for updating.
I have react running on localhost:3000 and the laravel-API running on localhost:5000.
This is the route in API
Route::put('updateSlide/{id}', 'SlidesController#updateSlide');
This is what is in the controller
public function updateImage(Request $request, int $id)
{
$image = $this->slideRepo->findSlideById($id)->image;
if ($image) {
$result = Storage::disk('ucmp')->delete($image);
}
if ($request->hasFile('image') && $request->file('image') instanceof UploadedFile) {
return $this->slideRepo->saveCover($request->file('image'));
} // return response()->json($data);
// data is an array (note)
return null;
}
public function updateSlide(Request $request, int $id)
{
$imageUrl=$this->updateImage($request, $id);
return response()->json($this->slideRepo->updateSlide([
'caption' => $request['caption'],
'image' => $imageUrl,
'url' => $request['url']
],$id));
}
This is the function sending to fetch
export const updateSlideApi = (token, _slide, id) => {
return {
url: `${BASE_URL}/api/updateSlide/${id}`,
opt: API.requestOptions("PUT",token,null,{ body: _slide }, true)
};
};
In my header i do not have the content-type.
I expect json data from the laravel API function but am having an error, " Can only throw objects"
PHP does not parse the body of a PUT request.
Use POST and add parameter _method with value PUT.
PHP put has given me tough time, use this function will save your time parsing it else method:
function parsePutRequest()
{
// Fetch content and determine boundary
$raw_data = file_get_contents('php://input');
$boundary = substr($raw_data, 0, strpos($raw_data, "\r\n"));
// Fetch each part
$parts = array_slice(explode($boundary, $raw_data), 1);
$data = array();
foreach ($parts as $part) {
// If this is the last part, break
if ($part == "--\r\n") break;
// Separate content from headers
$part = ltrim($part, "\r\n");
list($raw_headers, $body) = explode("\r\n\r\n", $part, 2);
// Parse the headers list
$raw_headers = explode("\r\n", $raw_headers);
$headers = array();
foreach ($raw_headers as $header) {
list($name, $value) = explode(':', $header);
$headers[strtolower($name)] = ltrim($value, ' ');
}
// Parse the Content-Disposition to get the field name, etc.
if (isset($headers['content-disposition'])) {
$filename = null;
preg_match(
'/^(.+); *name="([^"]+)"(; *filename="([^"]+)")?/',
$headers['content-disposition'],
$matches
);
list(, $type, $name) = $matches;
isset($matches[4]) and $filename = $matches[4];
// handle your fields here
switch ($name) {
// this is a file upload
case 'userfile':
file_put_contents($filename, $body);
break;
// default for all other files is to populate $data
default:
$data[$name] = substr($body, 0, strlen($body) - 2);
break;
}
}
}
return $data;
}

CakePHP 3 : display data from other model and pass parameter in url from action

I'm working on a project using CakePHP 3.x.
I have UserAddress, ServiceRequests, Service models.
There is a button on service/view/$id which when clicked will ask user to select address from service-requests/serviceArea which has a list of addresses added by user. service-requests/serviceArea view will contain a select button which when clicked will call add action in ServiceRequests controller with passing two parameters serviceId and userAddressId
This is the serviceArea function created by me.
public function serviceArea($id = null)
{
public $uses = array('UserAddress');
$service = $id;
$query = $userAddresses->find('all')
->where(['UserAddresses.user_id =' => $this->Auth->user('id')]);
$this->set(compact('userAddresses'));
$this->set('_serialize', ['userAddresses']);
}
How to display the address and also pass the $service parameter to the serviceArea view.
I am new to CakePHP, so if you think question is incomplete any edit to it will be appreciated instead of down-voting.
Thank You.
Edit 2
Thank for your answer #jazzcat
After changing my code according to yours and visiting http://domain.com/service-requests/service-area/$id. It is showing error as
Record not found in table "service_requests"
and pointing to the ServiceRequestsController on line no 33
The ServiceRequestController as containing line no 33 is
<?php
namespace App\Controller;
use App\Controller\AppController;
/**
* ServiceRequests Controller
*
* #property \App\Model\Table\ServiceRequestsTable $ServiceRequests
*/
class ServiceRequestsController extends AppController
{
/**
* isAuthorized method
*
*/
public function isAuthorized($user)
{
$action = $this->request->params['action'];
// The add and index actions are always allowed.
if(in_array($action, ['index', 'add', 'serviceRequests'])) {
return true;
}
// All other actions require an id.
if (empty($this->request->params['pass'][0])) {
return false;
}
// Check that the service request belongs to the current user.
$id = $this->request->params['pass'][0];
$serviceRequest = $this->ServiceRequests->get($id); // line : 33
if($serviceRequest->user_id == $user['id']) {
return true;
}
return parent::isAuthorized($user);
}
/* Other actions */
}
?>
This worked for me.
Just added the serviceArea action name in the isAuthorized method
if(in_array($action, ['index', 'add', 'serviceArea'])) {
return true;
}
and it's working fine as expected.
There is alot wrong with your code. Please read the docs
Is the table named user_addresses or user_address ?
You seem to mix the both.
The following would be the correct way to do it assuming your table is named user_addresses
public function serviceArea($id = null)
{
$this->loadModel('UserAddresses');
$userAddresses = $this->UserAddresses->find('all')
->where(['UserAddresses.user_id =' => $this->Auth->user('id')]);
// If you want to filter on the serviceArea ID aswell
if($id)
$userAddresses->andWhere(['id' => $id]);
// Setting SerivceArea ID to compact makes it available in view.
$serviceAreaId = $id;
$this->set(compact('userAddresses', 'serviceAreaId'));
$this->set('_serialize', ['userAddresses']);
}
This snippet:
$id = $this->request->params['pass'][0];
$serviceRequest = $this->ServiceRequests->get($id); // line : 33
Just checks if the first parameter passed to the method exists in ServiceRequests.
(That parameter could be anything, you have to keep that in mind when creating all your methods in that controller, that is to say the least.. bad)
I'm assuming that the service_requests table is associated with the users table and an user_id column exists in the service_requests table.
If that is the case this should work:
public function isAuthorized($user)
{
$action = $this->request->params['action'];
// The add and index actions are always allowed.
if(in_array($action, ['index', 'add'])) {
return true;
}
// Is not authorized if an argument is not passed to the method.
// Don't know why you'd want this , but sure.
if (empty($this->request->params['pass'][0])) {
return false;
}
// Check that the service request belongs to the current user.
$user_id = $this->Auth->user('id');
$serviceRequest = $this->ServiceRequests->find()->where(['ServiceRequests.user_id' => $user_id])->first();
if(!empty($serviceRequest)) {
return true;
}
return parent::isAuthorized($user);
}

CakePHP 2.5 Datasource, create and return response

I have a specific task to connect CakePHP web application to a remote restful server . I create a datasource, read method works great, but the api after save data return an array of processed data.
Looking for a way to return the data array and use in controller.
My Controller code
public function admin_generate()
{
$data = $this->request->data;
$data['path'] = 'special/generate';
$this->Tool->create();
if($this->Tool->save($data)){
// handle response ????
}
$this->set('data',$data);
$this->set('_serialize','data');
}
In datasource file
public function create(Model $model, $fields = null, $values = null)
{
$data = array_combine($fields, $values);
$api = $this->config['api_path'].$data['path'].'?auth_key='.$this->config['auth_key'];
$json = $this->Http->post($api, $data);
$response = json_decode($json, true);
if (is_null($response)) {
$error = json_last_error();
throw new CakeException($error);
}
return $response; // ??????
}
Can someone show me the correct way to use the api response data in the controller?
I found a solution, a few minutes after a post question. This can help one of you.
datasource
....
if (is_null($response)) {
$error = json_last_error();
throw new CakeException($error);
}
// SOLUTION
$model -> code = $response['code'];
$model -> key = $response['key'];
$model -> code_id = $response['code_id'];
return true;
.....
in controller
.....
if($this->Tool->save($data)){
unset($data['path']);
$data['code'] = $this->Tool->code;
$data['key'] = $this->Tool->key;
$data['code_id'] = $this->Tool->code_id;
}
.....

Symfony 2 how to call the renderView method in FormHandler?

I try to do a contact form with Symfony 2.4.1. My form is a simple contact one without an entity.
The following error happens in my handler :
FatalErrorException: Error: Call to undefined method Symfony\Component\Form\Form::render() in C:\Program Files\wamp\www\sf2\src\Open\OpcBundle\Form\Handler\ContactHandler.php line 75
And the form handler code :
<?php
// src/Open/OpcBundle/Form/Handler/Handler.php
namespace Open\OpcBundle\Form\Handler;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
class ContactHandler {
protected $request;
protected $form;
protected $mailer;
public function __construct(Form $form, Request $request, $mailer) {
$this->form = $form;
$this->request = $request;
$this->mailer = $mailer;
}
public function process() {
if ('POST' == $this->request->getMethod()) {
$this->form->handleRequest($this->request);
$data = $this->form->getData();
$this->onSuccess($data);
return true;
}
return false;
}
protected function onSuccess($data) {
$message = \Swift_Message::newInstance()
->setContentType('text/html')
->setSubject($data['sujet'])
->setFrom($data['courriel'])
->setTo('me#gmail.com')
->setBody($this->render('OpcOpenBundle:Opc:Mails/contact.html.twig',
array('ip' => $request->getClientIp(),
'nom' => $data['nom'],
'msg' => $data['msg'])
)
);
$this->get('mailer')->send($message);
$request->getSession()->getFlash()->add('success', 'Your email has been sent! Thanks!');
return $this->redirect($this->generateUrl('contact'));
}
}
So the problem is that I don't have an object/instance for the renderView() method to call the template mail with setBody in the function onSuccess()
Which object/instance should I use for ?
Thanks
PS: sorry for my english, i'm French!
It's Symfony\Bundle\TwigBundle\TwigEngine class. service name is 'templating'.
BTW, why is you handler is not service?

Refresh the view after I submitted POST params on deleting a record

My question is how can I refresh my view "search.ctp" to take into account the record I just deleted. The problem is the following.
My controller code
public function search() {
if ($this->request->is('post')) {
$this->set("isPost", TRUE);
$query = $this->data;
$output = $this->Question->find("all", array("conditions"=>array("Question.lectureId"=>$query["Lecture"]["Lecture"],
"Question.type"=>$query["Lecture"]["status"])));
$this->set("questions", $output);
} else {
$this->LoadModel("Lecture");
$outputL = array();
$for = $this->Lecture->find("all", array("fields" => array("_id", "title")));
foreach ($for as $key => $value) {
$outputL[$value["Lecture"]["_id"]] = $value["Lecture"]["title"];
}
$this->set("lectures",$outputL);
//
$statuses = array(
"" => "Select a question type",
"anonymousQuestion" => "anonymousQuestion",
"handUp" => "handUp",
"userQuestion" => "userQuestion"
);
$this->set("statuses", $statuses);
}
}
So the following happens;
I open the view "search.ctp" ("my admin interface"), set the 2 search params,
and use the submit button to post that data. Then my IF statement recognizes that as POSt and gives me back my query results. The problem is when i delete a record...
It redirects me back to my search action to enter the query params again... How do i just refresh the page with the same query params and NOT leave my view.
o forgot my delete function code:
public function delete($id = null) {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
$this->Question->id = $id;
if (!$this->Question->exists()) {
throw new NotFoundException(__('Invalid configuration'));
}
if ($this->Question->delete()) {
$this->Session->setFlash(__('Question deleted'));
return $this->redirect(array("action"=>"search"));
}
$this->Session->setFlash(__('Question was not deleted'));
$this->redirect(array('action' => 'search'));
}
As a workaround i made another function that does the same thing with GET request that my search function does with a POST request. Basically returns the data with the query params. And i used the Session helper to carry the query over to my other function. Dont know how smart that was, but it does the trick for me...
Still would be nice to know if someone has a solution where i dont have to make another function/view

Resources