Cakephp 3 & Ajax, send $.get additional data - json

I try to send custom data using $.get from jquery but cakephp 3 does not recognize the variables.
Here is my function in controller:
public function view($cat,$id,$page){
$comments = $this->Comments->find('all')->where(['category =' => $cat, 'AND' => ['category_id =' => $id]])->order(['comments.created' => 'DESC'])
->contain([
'Reports' => function($q){return $q->where(['user_id =' => $this->Auth->user('id')]);},
'Chars' => function($q){ return $q->select(['id','name','class','race','level','guild_id', 'user_id'])
->contain(['Guilds' => function($q){ return $q->select(['id','name']);
}]);
}])->limit(3)->page($page);
if($cat == 'Videos'){
$subject = $this->Comments->Videos->get($id);
}
$category = $cat;
$this->set(compact('subject','comments','category'));
}
}
And here's the .js
$('.more').click(function(){
$.get($(this).attr('href'),{cat:'Videos',id:'44',page:'2',function(data){
$('.coms').empty().append(data);
});
return false;
});
And the link:
<?= $this->Html->link('More', ['controller' => 'Comments','action' => 'view'], ['class' => 'btn btn-primary more']) ?>
The fix values in the .js is for the test, it works if I send the data in the link with $.get(href) but I want to know how to pass custom data in the $.get request.
Thank you for your help

CakePHP doesn't magically map query string parameters to method arguments, that's not even supported by routes.
You can access query string paramters via the request object
$this->request->query('cat');
See also http://book.cakephp.org/3.0/en/controllers/request-response.html#query-string-parameters

The solution
Hi, I did a little api to get the data I need from a json array.
So I created an ApiController to do all the ajax requests I need. Here is test example:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
class ApiController extends AppController
{
public function test($id)
{
$UsersTable = TableRegistry::get('Users');
$users = $UsersTable->find()->where(['id <' => $id]);
$this->set(compact('users'));
}
}
?>
I want to get the list of all my users from an ajax call (that's the worst idea ever but it's just for the test ;))
Now I need to enable json for this view. For this, I need to go in config/routes.php to add this:
Router::scope('/api', function($routes){
$routes->extensions(['json']);
$routes->connect('/test/*', ['controller' => 'Api', 'action' => 'test', '_ext' => 'json']);
});
Now when I go on http://localhost/mywebsite/api/test/100, I have a json array of all the users with an id < 100, ready to get pulled by an ajax script.
'_ext' => 'json'
means you don't have to go on api/test.json to display the json array
Now on a random view in a random controller, I put a button to try all this and I call my javascript file to do my ajax request.
<button class="test">Test button</button>
<?= $this->Html->script('test', ['block' => true]) ?>
Now in my test.js:
$(document).ready(function(){
var value = 100;
$('.test').click(function(){
$.get('/api/test/' + value, function(data){
console.log(data);
});
});
});
I click the button and the log shows an array with all the users I wanted in my console when I push F12 (on chrome).
Hope this will help someone

Related

ACF acf_form on admin page works, but when it is loaded in via ajax it breaks

I'm using acf_form() to embed a form in a metabox on the admin page using this code (simplified):
$submitted_user_id = 'user_3';
$form_settings = array(
'fields' => ['field_625008b509dca'],
'form_attributes' => array(
'method' => 'POST',
'action' => admin_url("admin-post.php"),
),
'post_id' => $submitted_user_id,
);
acf_form( $form_settings );
..and calling the requisite acf_form_head() in admin_init as such:
function append_acf_form_head() {
acf_form_head();
}
add_action( 'admin_init', 'append_acf_form_head', 1 );
This works fine, and updates the values on submit. However I want to pull this form in via ajax, in order to pass the user_id from a select filter above.
The ajax is also working perfectly, and pulling in the form with the passed user_id, however on submission the form does not save the data, and redirects to 'wp-admin/admin-post.php'.
This is the php code for the ajax functionality in functions.php:
add_action( 'wp_ajax_test_action', 'test_action' );
function test_action() {
// Same acf_form() function as above
wp_die()
}
And finally the JS:
$('button#support-ticket-user-filter').on('click', function(e) {
e.preventDefault();
var data = {
'action': 'test_action',
'user_id': $('select#get_user_id').val()
};
$.post(ajaxurl, data, function(response) {
$('#listings-result').append( response );
});
});
Any ideas why it would work perfectly in the first case, but not in the second? Perhaps it's related to the ajaxurl?
Many thanks!
For anyone looking for the solution; I've found a slightly hacky approach which does the trick for now. The ACF Support team mentioned this wasn't out the box functionality but has now been included as a feature request. For those trying to achieve this the trick is to permanently embed a 'dummy form' which loads the necessary stuff to make it all work - then kind of hook this into the form pulled in via ajax:
So, in the meta box a permanent dummy form is embedded:
// This dummy form is required to load all the acf stuff for the ajax version
$dummy_form_settings = array(
// Do not declare any fields
'post_id' => $submitted_user_id, // Make sure the ID corresponds ( for users in my case )
'form' => true,
);
acf_form( $dummy_form_settings );
All we want from this dummy form is the 'update' button - which is the one that actually works, as opposed to the one in the form pulled in via ajax. So that function will remove the submit button like this:
$form_settings = array(
'fields' => ['field_625008b509dca'],
'form_attributes' => array(
'method' => 'POST',
),
'html_before_fields' => sprintf(
'<input type="hidden" name="user_id" value="' . $submitted_user_id . '">',
),
'post_id' => $submitted_user_id,
'form' => true,
'html_submit_button' => '', // The important bit
);
acf_form( $form_settings );
wp_die();
Now your essentially left with a single form that submits properly.

Create dynamic request object in Laravel

I was looking for help creating an object of the type Illuminate\Http\Request. This article helped me understand the mechanism of the class, but I did not get the desired result.
Create a Laravel Request object on the fly
I'm editing the development code passed to me by the customer. The code has a function that gets a request parameter from vue and translates it to JSON:
$json = $request->json()->get('data');
$json['some_key'];
This code returned an empty array of data:
$json = $request->request->add([some data]);
or
$json = $request->request->replace([some data]);
this one returned an error for missing the add parameter
$json = $request->json->replace([some data]);
A variant was found by trying and errors. Maybe, it help someone save time:
public function index() {
$myRequest = new \Illuminate\Http\Request();
$myRequest->json()->replace(['data' => ['some_key' => $some_data]]);
$data = MyClass::getData($myRequest);
}
..
class MyClass extends ...
{
public static function getData(Request $request) {
$json = $request->json()->get('data');
$json['some_key'];
In addition, there are other fields in the class that you can also slip data into so that you can pass everything you want via Request
$myRequest->json()->replace(['data' => ['some_key' => $some_data]]);
..
$myRequest->request->replace(['data' => ['some_key' => $some_data]]);
..
$myRequest->attributes->replace(['data' => ['some_key' => $some_data]]);
..
$myRequest->query->replace(['data' => ['some_key' => $some_data]]);
$myRequest = new \Illuminate\Http\Request();
$myRequest->setMethod('POST');
$myRequest->request->add(['foo' => 'bar']);
dd($request->foo);
This from the link you shared works, give it a try. Thanks for sharing that link!

How to populate dropdown from database laravel 5.x

Controller side:
$regs = Model::all('id','name');
return view('aview',compact('regs'));
View side:
{{ Form::select('id', $regs) }}
The dropdown gets rendered and populated but displays JSON objects such as {"id:1","name: Aname"} instead of displaying Aname and setting the post value to 1
Try this
In your controller
$regs = Model::pluck('name','id');
Keep your view same
Hope this will work
You can populate like this:
{!! Form::select('id', $regs->lists('name', 'id'), null, ['class' => 'form-control']) !!}
Form::select accepts four parameters:
public function select($name, $list = [], $selected = null, $options = []);
The name of the html field
the list of options
the selected value
an array of html attributes
You can generate the list by using
$regs = Model::all('id','name');
$plucked = $regs->pluck('name', 'id');
// $plcuked = ['id1' => 'name1', 'id2' => 'name2' ...]
And the blade code should look like this
{{ Form::select('name', $plucked, null, ['class' => 'form-control']); }}
I maybe making this problem a bit complicated but I think its worth using the plugin.
You can take the use of very popular plugin - Select2. This plugin of jQuery helps you to fetch data from server and populate the fetched data into our dropdown in minutes. Your code goes like this.
// Code in your Controller Method
$regs = Model::all();
$data = [];
foreach($regs as $reg) {
$data[] = [
'id' => $reg->id,
'text' => $reg->name
];
}
return json_encode(['items' => $data]);
// Code in your desired View
<select id="select_items"></select>
// Code in js
$('#select_items').select2({
ajax: {
url: '/example/api', // <--------- Route to your controller method
processResults: function (data) {
return {
results: data.items
};
}
}
});
You can also integrate search options using this plugins as it helps you to fetch results based on your search keywords (for more see Select2 Examples). Hope this helps you to solve your problem.

CakePHP 3 - Can't return proper json when debug mode = true

I'm new to stackoverflow, and I've just started to play around with CakePHP 3.
I've run into a weird problem:
I'm sending an ajax-request (form submit) to the controller, and I expect to get a proper json-response back. It works fine when I set debug mode to false in config/app.php, but when it's set to true, I get an error-message in the browsers console, and the responsetext seem to be html. I'm calling the action with the .json extension in the url.
I've linked screenshot of the console where the first response is with debug mode set to false, and the second set to true:
I have enabled the extensions in config/routes.php:
Router::scope('/', function (RouteBuilder $routes) {
$routes->extensions(['json', 'xml']);
(...)
Here's the controller-code:
public function getUserStats() {
$this->log($this->request->data, 'debug');
if (($this->request->is('post'))) {
$this->log('getCategories(): Post-request is received.', 'info');
$usersTable = TableRegistry::get('Users');
$q = $usersTable->find('statsByUsers', $this->request->data);
$users = $q->all();
// Calculating total amount per user.
foreach ($users as $u) {
foreach ($u->purchases as $p) {
$u->total += $p->total;
}
}
$this->log($users, 'debug');
$this->set('users', $users);
$this->set('_serialize', ['users']);
}
}
Here's the model code:
public function findStatsByUsers(Query $query, array $options) {
debug($options);
$options['dates'] = $this->getConvertedDates($options);
$query
->contain([
'Purchases' => function($q) use($options) {
return $q
->select(['id', 'total' => 'amount * count', 'purchase_date', 'user_id'])
->where(['purchase_date BETWEEN :fromDate AND :toDate',])
->bind(':fromDate', $options['dates']['fromDate'], 'datetime') // Binds the dates to the variables in where-conditions
->bind(':toDate', $options['dates']['toDate'], 'datetime');
}
])
->where([
'Users.id IN ' => $options['users'],
'Users.active' => true
]);
return $query;
}
I hope I've given you enough information so that you can help me solve this.
CakePHP version: 3.3.2
Looking at the bit of output that is visible in the screenshot
<div class="cake-debug-output"> ...
that HTML is output generated by the debug() function.
Look closely at your model code, and you should spot the call to the function. Remove it, and you should be good.
btw, the source of the call can be found in the first <span> element in the <div>, so if you experience similar problems in the future make sure to check that.
<?php
use Cake\Core\Configure;
// your class ,...
public function getUserStats() {
$this->log($users, 'debug');
Configure::write('debug',false); // DISABLE
$this->set('users', $users);
$this->set('_serialize', ['users']);
}

Submit AngularJS form with CodeIgniter

Let me preface this by saying I'm new to AngularJS & CodeIgniter.
Trying to create a single page app. In the center it displays news stories. On the side is a form to submit new stories. I'm to the point where the stories display fine from the DB. But when I try to create new stories from the form on the side, it enters 0 into the DB. I assume I have an issue with my function in the model. And it's probably as basic as not having the information encoded correctly to pass between MVC.
index.php
<div class="span2" ng-controller="NewStoryCtrl">
<h4>New Story</h4>
<form name="newStory">
<label for="title">Title: </label>
<input type="text" name ="title" ng-model="news.title" required>
<label for="text">Text: </label>
<textarea type="text" name="text" ng-model="news.text"required></textarea>
<button ng-click="createNews()">Submit</button>
</form>
controller.js
function NewStoryCtrl($scope, $http) {
$scope.news = {title:$scope.title, text:$scope.text};
$scope.createNews = function(){
$http.post('/ci/index.php/news/create/',$scope.news);
};}
news.php (controller)
public function create() {
$this->news_model->set_news();
}
news_model.php (model)
public function set_news() {
$this->load->helper('url');
$slug = url_title($this->input->post('title'), 'dash', TRUE);
$data = array(
'title' => $this->input->post('title'),
'slug' => $slug,
'time' => time(),
'text' => $this->input->post('text')
);
return $this->db->insert('news', $data);
}
The stuff in the model is leftover from my initial CI news tutorial. That's why I assume the error is here.
What's the best way to pass the information from the controllers.js to the model?
As expected, my issue was with not getting the right type of data. Controller was expecting a variable, but in Angular controller I was passing it as JSON. I hadn't ever gone through decoding.
news.php (controller)
public function create() {
$data = json_decode(file_get_contents('php://input'), TRUE);
$this->news_model->set_news($data);
}
And then in the model, I just needed to pass it as a parameter to set_news(). I ended up changing some variable names, just for personal clarification.
*news_model.php*
public function set_news($data) {
$this->load->helper('url');
$slug = url_title($data['title'], 'dash', TRUE);
$retval = array(
'title' => $data['title'],
'slug' => $slug,
'time' => time(),
'text' => $data['text']
);
return $this->db->insert('news', $retval);
}
I haven't used Angular.js, but your data format is probably correct. For example, Backbone sends a single $_POST variable called model with json encoded data, as I have used it.
It is imperative that you use Firebug, Webdev or other tools to see what is going on when you try to do AJAX work like this; otherwise you will go crazy . Look at the variable being sent to your backend - it is probably described, an encoded single var you will need to collect, json_decode, CLEAN & VALIDATE and then use.