Zend Framework ajaxLink params not being sent to ctr/action method - zend-framework

I have a simple ajaxLink to a controller. It works without the params, but when I add a param I get an error:
Warning: Missing argument 1 for Ez_ContactsController::testyAction()
The params are required and I see them in the jquery that ZF creates. here is the JS that gets generated (/ez is my module):
$(document).ready(function() {
$('a.ajaxLink1').click(function() { $.post('/ez/contacts/testy', {"param1":"1","param2":"456"}, function(data, textStatus) { $('#testy').html(data); }, 'html');return false; });
});
Here is my ajaxLink:
<div id="testy"></div>
<?= $this->ajaxLink("Example 2",
"/ez/contacts/testy",
array('update' => '#testy',
'class' => 'someLink'),
array('param1' => '1',
'param2' => '456')); ?>
Thanks for any help

I found the answer.
You don't send the vars directly to the function, they are sent via GET or POST.
Here is how I got the vars.
$param1 = (int)$this->_request->getParam('param1');
$param2 = (int)$this->_request->getParam('param2');
Here is the entire function:
public function testyAction(){
//The request was made with JS XmlHttpRequest
$this->_helper->viewRenderer->setNoRender(); //Will not render view
$this->_helper->Layout->disableLayout(); // Will not load the layout
$param1 = (int)$this->_request->getParam('param1');
$param2 = (int)$this->_request->getParam('param2');
echo 'testy 123. params sent were: '.$param1.', '.$param2;
}

Related

Drupal-8 Modal does not handle errors on login

I have used 'use-ajax' class to render login form in a modal. I want to handle validation errors on same modal without closing it. On successful login it is redirecting correctly, but when an error occurs it closes modal and redirecting to login page i.e user/login and displaying errors on that page. I tried to use ajax callback to display error on modal itself by altering the form which is working. But, it is giving me drupal ajax error. Here is my code :
$form['#prefix'] = '<div id="modal-form">';
$form['#suffix'] = '</div>';
$form['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -10,
];
$form['actions']['submit']['#ajax'] = array(
'callback' => 'setMessage',
'wrapper' => 'modal-form',
);
=========================================================================
function setMessage(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
$response = new AjaxResponse();
if ($form_state->hasAnyErrors()) {
$response->addCommand(new ReplaceCommand('#modal-form', $form));
}
else {
$command = new CloseModalDialogCommand('#modal-form', FALSE);
$response->addCommand($command);
}
return $response;
}
The above code giving me session id also but due to drupal ajax error it does not redirect on success by closing modal.
If I go with non-ajax ie. if I remove the ajax callback function it works on success but errors are not displaying on modal.
First, check if you have added redirection related changes using hook_login in your module file. You can remove that redirection related changes and handle redirection in your callback function.
function setMessage(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
$response = new AjaxResponse();
$current= \Drupal::currentUser();
if ($form_state->hasAnyErrors()) {
$response->addCommand(new ReplaceCommand('#modal-form', $form));
}
else if (!$current->id()) {
$response->addCommand(new ReplaceCommand('#modal-form', $form));
}
else {
$command = new RedirectCommand(' ');
return $response->addCommand($command);
}
return $response;
}
On success it will close the modal and will redirect correctly. If you found any error or if you are not logged in it will stay on modal form.

Slim framework 3: how to get parameters from a redirect from a post route inside a get route

This may seem a simple example but I am stuck. I am watching a tutorial where we see a contact form that has its own get route to render a view that contains the already said contact form.
$app->get('/contact',function (Request $request, Response $response){
return $this->view->render($response,'contact.twig');
})->setName('contact');
Then we have a post that gets the posted data through that form (notice I am passing the data that has been collected from the form).
$app->post('/contact',function ($request,$response){
$data = $request->getParams();
//var_dump($data);
return $response->withRedirect($this->router->pathFor('contact.confirmed', ['data' => $data]));//https://github.com/slimphp/Slim/issues/1933
})->setName('contact');
Finally we have another get route to render a confirmation view that lets the user know that the information has been submitted successfully.
$app->get('/contact/confirmed',function(Request $request, Response $response, $data){
echo 'params are';
var_dump($data);//They never show! :(
return $this->view->render($response,'contact_confirm.twig',[
'data' => $request->getParams(),
]);//https://github.com/slimphp/Slim/issues/1579
})->setName('contact.confirmed');
In that confirmation view, I want to retrieve the data submitted in the post route just to call the user by their name but I get an error saying that $data is empty.
I have been struggling on how to retrieve the user's name.
As a workaround, I have solved it by rendering the view right from the post route ...
$app->post('/contact',function ($request,$response){
$data = $request->getParams();
//var_dump($data);
return $response->withRedirect($this->router->pathFor('contact.confirmed', ['data' => $data]));//https://github.com/slimphp/Slim/issues/1933
})->setName('contact');
but then I wonder why bothering to use withRedirect() function?
My question is, how do I pass data or parameters from a post route to a get route wher you use a withRedirect() function? And in the get route, how do you retrieve those parameters? So I can pass them to its corresponding view.
Solved
Thanks to jmattheis this is how I solved it:
I just happened to learn how to use controllers in slim framework 3, so the ContactController.php looks like:
<?php
namespace App\Controllers\contact;
use App\Controllers\Controller;
class ContactController extends Controller
{
public function show($request,$response)
{
return $this->c->view->render($response,'contact.twig');
}
public function store($request,$response)
{
echo 'storing comments in db ...';
$data = $request->getParams();
//var_dump($data);
//echo 'Name is: '.$data['name'];
$this->c->flash->addMessage('data', $data);
return $response->withRedirect($this->c->router->pathFor('contact.success'));
}
public function success($request,$response,$data)
{
//echo 'Data to be sent in the redirect: ';
$data = $this->c->flash->getFirstMessage('data');
//var_dump($data);
//die();
return $this->c->view->render($response,'contact_success.twig',compact('data'));
}
}
And I added the following code
session_start();
ini_set('date.timezone', 'America/Mexico_City');
right before
$app = new App([
'settings' => [
'displayErrorDetails' => true
]
]);
And that did the trick.
You can't transfer data over a redirect. The second parameter from the pathFor method on the router is the array for the named paramters. That would be f.ex. id in the route /user/{id} then you'd had to put ['id' => 1] in it.
If you $data has a simple structur, then you could put them in the 3rd parameter which are the query params and later read them out with $request->getQueryParams()
$this->router->pathFor('contact.confirmed', [], $data);
Alternative, you could put the data in a session variable, slimphp/Slim-Flash is a library who that.
Example:
$app->post('/contact',function ($request,$response){
$data = $request->getParams();
$this->flash->addMessage('data', $data);
return $response->withRedirect($this->router->pathFor('contact.confirmed'));
})->setName('contact');
$app->get('/contact/confirmed',function(Request $request, Response $response, $data){
$data = $this->flash->getFirstMessage('data');
// ...
});
Assuming that confirmation template is rendered only after form is being processed, there is no need to declare a separate GET route for such view.
So, keep the route that renders the form:
// This route renders the contact form.
$app->get('/contact', function ($request, $response) {
return $this->view->render($response, 'contact.twig');
})->setName('contact');
And render contact_confirm.twig only as result of form being posted:
// This route is contact form processor.
$app->post('/contact', function ($request, $response) {
// Get submitted data.
$formData = $request->getParams();
// Process form data, e.g. store it, sending it somewhere...
// Render confirmation template, passing user name as template parameter.
$templateParams = [
'userName' => $formData['userName'] ?? 'Name unknown';
];
return $this->view->render($response, 'contact_confirmed.twig', $templateParams);
});

Wordpress plugin: Working with REST api

Before I start, I want to tell you guys that I have no experience in anything Wordpress related. I do have worked in PHP and Codeigniter before.
User Case
The user enters a preferred feature in a form (Air conditioning, etc.).
When the user submits the form, the feature will be send to a REST API.
The results of the REST API ( a list of cars with AC ) will be shown on the page.
It should roughly look something like this.
What i have so far
An empty plugin that is shown in the Wordpress admin panel.
Question(s)
How do create the front-end for this plugin?
How and where do I create the form action?
How do I access the form action?
What I have/know so far
I know there are some action hooks that will place your content in the header and footer by creating something like:
<php add_action('wp_footer', 'mp_footer'); ?>
In your empty plugins php file place this:
function get_search_results(){
$args = array( 's' => $_GET['term'] );
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
echo '<li>'.get_the_title().'</li>';
}
} else {
echo "Nothing Found";
}
die();
}
add_action( 'wp_ajax_get_search', 'get_search_results' );
add_action( 'wp_ajax_nopriv_get_search', 'get_search_results' );
function get_searchbox( $atts ){
ob_start(); ?>
<form id="searchform">
<input type="text" id="searchbox">
<button type="submit">Search</button>
</form>
<ul id="search-result"></ul>
<?php
$output = ob_get_clean();
return $output;
}
add_shortcode( 'searchbox', 'get_searchbox' );
function add_search_script() {
wp_enqueue_script( 'search', plugins_url( '/search.js' , __FILE__ ), array( 'jquery' ) );
wp_localize_script( 'search', 'search_ajax', array( 'url'=>admin_url( 'admin-ajax.php' ), 'action'=>'get_search' ) );
}
add_action( 'wp_enqueue_scripts', 'add_search_script' );
In your plugin's directory create a new javascript file - search.js and place this:
jQuery(function($){
$('#searchform').submit(function(e){
e.preventDefault();
$.ajax({
url: search_ajax.url,
data: { 'action': search_ajax.action, 'term': $('#searchbox').val() }
}).done(function(r) {
$('#search-result').html(r);
});
});
});
Now you can use shortcode [searchbox] in your wordpress page to get your searchbox.
In php you can get same result with <? echo do_shortcode('[searchbox]') ?>
Explanation:
When we add [searchbox] shortcode, it is processed and replaced with a form via get_searchbox() function.
In jQuery code On form submit we are sending an action : get_search (defined in wp_localize_script).
Server receives that request via wp_ajax_get_search and processes get_search_results() and returns an output.
In jQuery done(function(r){ r is the response from server. Use that data to manipulate your html.
action is the essential part of REST api in wordpress. We need not have a url. Instead we define an action and for that action return a response.
Once you understand this, modify the action and response according to your need.
Helpful articles: Daniel's, wpmudev

Load Form from module into custom page template

I have successfully added my own form (from the same module) into my custom template, but now I wish to load the taxonomy add term form (used by ubercart I think for product categories in the catalog vocab) into my template.
I have gotten this far with my module - filename simpleadmin.module
/**
* #file
* A module to simplify the admin by replacing add/edit node pages
*/
function simpleadmin_menu() {
$items['admin/products/categories/add'] = array(
'title' => 'Add Category',
'page callback' => 'simpleadmin_category_add',
'access arguments' => array('access administration pages'),
'menu_name' => 'menu-store',
);
return $items;
}
function simpleadmin_category_add() {
module_load_include('inc', 'taxonomy', 'taxonomy.admin');
$output = drupal_get_form('taxonomy_form_term');
return theme('simpleadmin_category_add', array('categoryform' => $output));
}
function simpleadmin_theme() {
return array(
'simpleadmin_category_add' => array(
'template' => 'simpleadmin-template',
'variables' => array('categoryform' => NULL),
'render element' => 'form',
),
);
}
?>
And as for the theme file itself - filename simpleadmin-template.tpl.php, only very simple at the moment until I get the form to load into it:
<div>
This is the form template ABOVE the form
</div>
<?php
dpm($categoryform);
print drupal_render($categoryform);
?>
<div>
This is the form template BELOW the form
</div>
Its telling me that it is
Trying to get property of non-object in taxonomy_form_term()
and throwing up an error. Should I be using node_add() and passing the nodetype?
To render a taxonomy term form, the function should be able to know the vocabulary to which it belongs to. Otherwise how would it know which form to show? I think this is the proper way to do it.
module_load_include('inc', 'taxonomy', 'taxonomy.admin');
if ($vocabulary = taxonomy_vocabulary_machine_name_load('vocabulary_name')) {
$form = drupal_get_form('taxonomy_form_term', $vocabulary);
return theme('simpleadmin_category_add', array('categoryform' => $form));
}
To redirect your form use hook_form_alter
function yourmodule_form_alter(&$form, &$form_state, $form_id) {
//get your vocabulary id or use print_r or dpm for proper validation
if($form_id == 'taxonomy_form_term' && $form['#vocabulary']['vid'] = '7' ){
$form['#submit'][] = 'onix_sections_form_submit';
}
}
function yourmodule_form_submit($form, &$form_state) {
$form_state['redirect'] = 'user';
}

Zend: Redirect from form without validation

I have a form for the creation of new "groups". I now added a small "go back" image with which the user should be able to go back one step. I don't know why, but when I click this new image, the controller and action used for the form which I want to leave (/admin/creategroup) is called again with HTTP POST set. Therefore, the form validation is done, and I'm stuck at this form with the validation errors displayed.
This is a snippet of the code from my form with both image-buttons. I wan't the "go back"-image to redirect me to the specified controller without validating the form:
$this->addElement('image', 'btnBack', array (
'name' => 'btnBack',
'id' => 'btnBack',
'label' => '',
'title' => 'Go back',
'alt' => 'Go back',
'src' => '/img/undo.png',
'onClick' => "window.location='/admin/groupoverview'"
));
$this->addElement('image', 'btnSave', array (
'name' => 'btnSave',
'id' => 'btnSave',
'label' => '',
'title' => 'Save this new group',
'alt' => 'Save this new group',
'src' => '/img/save.png',
'onClick' => "document.forms[0].submit();"
));
Edit:
I already thought of the possibility to check in /admin/creategroup whether it was called from the 'btnBack'-image or the 'btnSave'-image and skip form validation and redirect correctly if the source was the 'btnBack'-image.
I just think that there should be a nicer solution to directly redirect from the form and circumvent calling /admin/creategroup again.
Edit2:
My view script:
<div id="createGroupMask">
<br/>
Use the form below to create a new group
<?php
$this->form->setAction($this->url());
echo $this->form;
?>
</div>
My action in the controller:
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// Data for new group is valid
...
} else {
// Form data was invalid
// => This is where I land when pressing the 'back' image
// No further code here
}
}
$this->view->form = $form;
}
Now there is something to work with:
The isValid() loop is incorrect, your form will never evaluate as inValid with respect to the elements you've presented, you will never get to the else.
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// Data for new group is valid
...
} else {
/* This is incorrect */
// Form data was invalid
// => This is where I land when pressing the 'back' image
// No further code here
}
}
$this->view->form = $form;
}
My problem is that I'm not sure what is going to be submitted from your form, I'm not really familiar with how your using "onClick" and what I presume is javascript. It looks like element btnBack should redirect on click and element btnSave should POST. However this does not seem to be happening.
I have done this type of thing in PHP and ZF with submit buttons, perhaps the flow of what I did will help:
NOTE: for this type of flow to work you must give the button element a label. The label is used as the submit value.
//psuedoCode
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
//I would probably opt to perform this task with a switch loop
if ($form->getValue('btnBack') === some true value) {
$this->_redirect('new url');
}
if ($form->getValue('btnSave') === some true value) {
//Process and save data
}
} else {
//Display form errors
}
$this->view->form = $form;
}
I think when all is said and done the crux of your problem is that you did not give your button elements a label.
I tried adding labels to my images, but this didn't work.
I also tried to use the isChecked() method on my btnBack-image like this:
if ($form->btnBack->isChecked()) {
// 'Go back' image was clicked so this is no real error, just redirect
}
This didn't work either.
I finally was able to check which image was clicked via the following method as answered in Zend form: image as submit button:
public function creategroupAction()
{
$form = new Application_Form_CreateGroup();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
// Data for new group is valid
...
} else {
// Form data was invalid
if (isset($this->_request->btnBack_x)) {
// 'Go back' image was pressed, so this is no error
// -> redirect to group overview page
$this->_redirect('/admin/groupoverview');
}
}
}
$this->view->form = $form;
}
I guess this doesn't thoroughly answer the original question as the validation is still done and I'm only checking for this 'special case' where the 'Go back' image was clicked, but I'll mark it as answered anyways.
Tim Fountain suggested an even cleaner approach in my somewhat related question:
Zend forms: How to surround an image-element with a hyperlink?