Yii2 Show/Hide kartik treeview nodes - treeview

I am using Kartik Tree Manager. I am able to add, remove, update nodes. There is more requirement, that is to show/hide nodes on the basis of user access. i.e. when a user is given a specific node(s) then only that particular node(s) with all the child (if any) should be shown.
What I have done so far?
I have created a table user-node in which I am assigning a node id to a user as shown below
What I want to do
Now I want to show only the specified node with its child node only and hide other nodes to that user
Controller
For now, there are two views in which I am rendering the tree structure but in the future, there shall be more
My front page
public function actionIndex()
{
if(Yii::$app->user->isGuest){
$this->redirect(Yii::$app->urlManager->createUrl('site/login'));
}
return $this->render('index');
}
Itself tree-manager node controller
/**
* View, create, or update a tree node via ajax
*
* #return mixed json encoded response
*/
public function actionManage()
{
static::checkValidRequest();
$data = static::getPostData();
$nodeTitles = TreeSecurity::getNodeTitles($data);
$callback = function () use ($data, $nodeTitles) {
$id = ArrayHelper::getValue($data, 'id', null);
$parentKey = ArrayHelper::getValue($data, 'parentKey', '');
$parsedData = TreeSecurity::parseManageData($data);
$out = $parsedData['out'];
$oldHash = $parsedData['oldHash'];
$newHash = $parsedData['newHash'];
/**
* #var Module $module
* #var Tree $treeClass
* #var Tree $node
*/
$treeClass = $out['treeClass'];
if (!isset($id) || empty($id)) {
$node = new $treeClass;
$node->initDefaults();
} else {
$node = $treeClass::findOne($id);
}
$module = TreeView::module();
$params = $module->treeStructure + $module->dataStructure + [
'node' => $node,
'parentKey' => $parentKey,
'treeManageHash' => $newHash,
'treeRemoveHash' => ArrayHelper::getValue($data, 'treeRemoveHash', ''),
'treeMoveHash' => ArrayHelper::getValue($data, 'treeMoveHash', ''),
] + $out;
if (!empty($data['nodeViewParams'])) {
$params = ArrayHelper::merge($params, unserialize($data['nodeViewParams']));
}
if (!empty($module->unsetAjaxBundles)) {
$cb = function ($e) use ($module) {
foreach ($module->unsetAjaxBundles as $bundle) {
unset($e->sender->assetBundles[$bundle]);
}
};
Event::on(View::class, View::EVENT_AFTER_RENDER, $cb);
}
TreeSecurity::checkSignature('manage', $oldHash, $newHash);
return $this->renderAjax($out['nodeView'], ['params' => $params]);
};
return self::process(
$callback,
Yii::t('kvtree', 'Error while viewing the {node}. Please try again later.', $nodeTitles),
null
);
}
How can I achieve it? Any help would be highly appreciated.

One way to achieve hide/show some nodes may be as follows:
In views you should have your db table names.
Look for the table name you are interested in.
Inside the folder of the table name there should be files names something like: _form.php, _script.php and index.php
The index.php file should have some use among of which there should be:
...
use kartik\tree\TreeView;
use kartik\tree\Module;
...
After these use statements, you can add this code:
/** #var integer $uid */
// get current logged in user id.
// this is used to control showing tree content, and
// to control form fields.
if (isset(Yii::$app->user)) {
$uid = Yii::$app->user->getId();
}
So now the logged in user id is saved in variable $uid
In the same index.php file you should have code that renders the tree view. Something starts with: echo TreeView::widget
Inside this TreeView::widget([.. you can add a query that renders only current logged in user content, like this:
'query' => YourTableName::find()->where(['user_id' => $uid])->addOrderBy('root, lft'),
... Other settings ...
If you want the admin(s) to see or change the content, you can add a Controller for example named AdminController, then in this index.php TreeView::widget you can add more options like this:
echo TreeView::widget([
'query' => YourTableName::find()->where(['user_id' => $uid])->addOrderBy('root, lft'),
'headingOptions' => ['label' => 'YourLableName'],
//'rootOptions' => ['label' => '<span class="text-success">Root</span>'],
'fontAwesome' => false,
'isAdmin' => true,
'showInactive' => AdminController::isAdmin(),
'displayValue' => 0,
'showIDAttribute' => true,
'emptyNodeMsg' => ' type some msg here ... .',
'showCheckbox' => false,
'multiple' => false,
'options' => ['id' => 'treeID'],
'allowNewRoots' => false,
'toolbar' => [
'create' => ['alwaysDisabled' => true],
//'remove' => ['alwaysDisabled' => !(AdminController::isAdmin())],
// 'move-up' => ['alwaysDisabled' => !(AdminController::isAdmin())],
// 'move-down' => ['alwaysDisabled' => !(AdminController::isAdmin())],
// 'move-left' => ['alwaysDisabled' => !(AdminController::isAdmin())],
// 'move-right' => ['alwaysDisabled' => !(AdminController::isAdmin())],
//'remove' => false,
],
'cascadeSelectChildren' => false,
//'softDelete' => false,
'iconEditSettings'=> [
'show' => 'list',
'listData' => [
// 'folder' => 'Folder',
'file' => 'File',
'star' => 'Star',
'bell' => 'Bell',
// 'phone' => 'Phone',
]
],
'cacheSettings' => ['enableCache' => true],
'nodeAddlViews' => [
Module::VIEW_PART_1 => '#app/views/mappings/_form',
],
]);
This is just a small start, but you can take it further. For example suppose the user is not logged in or suppose you want to show some nodes any way. In these cases you can use switch case statement and check for example if $uid is not defined (it is not set because the user is not logged in) in this case, you can ask the user to log in or render or show a different tree view:
switch ($SomeVariable) {
case "case_to_check":
echo TreeView::widget([
...
'query' => TableName::find()->where(['user_id' => $uid])->addOrderBy('root, lft'),
...
break;
case "another_case":
echo TreeView::widget([
...
break;
default:
echo TreeView::widget([
...
== You can also add html select at the top of index.php, something like this:
<select name="Give_any_name_you_like" size=1 class="btn btn-primary" style="margin-bottom: 0.5em; margin-left: 0.5em; ">
<option value="0">Select Node</option>
<option value="1">mynodes</option>
<option value="2">othernodes</option>
<option value="3">allnodes</option>
</select>
then use java script to filter and capture the selected value, then you can use this vale in switch case to show certain nodes. You can place the java script code inside <?php block and before switch case or echo TreeView::widget([ . java script code may look something like this:
$this->registerJs("
$('select[name=" . "The_name_you_give_in_select" . "]').change(function(){
var value = $(this).val();
switch(value) {
case '1':
window.location.href = \"your-page-name?what=mynodes\" ;
break;
case '2':
window.location.href = \"your-page-name?what=othernodes\" ;
break;
default:
window.location.href = \"your-page-name?what=allnodes\" ;
}
});", View::POS_READY);
=== Then you check for the value of what in switch cases and use it to filter which tree node to show. Something like this code just below above java script code:
/** #var integer $The_name_you_give_in_select */
// get value from selection menu.
// this is used to filter and show desired tree.
if (isset($_GET['what'])) {
$The_name_you_give_in_select = $_GET['what'];
} else {
$The_name_you_give_in_select = "defaultcase";
}
// Then in switch case:
switch ($The_name_you_give_in_select) {
case "mynodes":
echo TreeView::widget([
...
break;
Case "othernodes":
echo TreeView::widget([
...
break;
default:
echo TreeView::widget([
...
=============
=== Also you may want to do some changes in views/your_table_name/_form.php
In _form.php you can also control what fields to show, what fields to make editable or read only, etc. something like this:
== _form.php:
...
/** #var integer $userid */
// save current node user id in var $userid
// to be used to control form fields
$userid = $node->user_id;
...
if(isset($userid)){
$username = Yii::$app->user->identity;
}
...
<div class="your-form">
...
<?= $form->field($node, 'annotation')->textarea(['rows' => 6, 'readonly' => !(Yii::$app->user->identity->id == $userid or AdminController::isAdmin())]) ?>
<?= $form->field($node, 'comments')->textarea(['rows' => 6, 'readonly' => !(Yii::$app->user->identity->id == $userid or AdminController::isAdmin())]) ?>
<!-- <?/*= $form->field($username, 'username')->textInput(['maxlength' => true, 'readonly'=>true])->label('Created by User') */?>-->
<?= $form->field($node, 'user_id')->textInput(['readonly'=>true]) ?>
<?= $form->field($node, 'date_added')->textInput(['placeholder' => 'Date Added', 'readonly'=>true]) ?>
</div>
=========
=== The AdminContoler.php may look something like this:
<?php
namespace app\controllers;
use Yii;
...
class AdminController extends Controller
{
/**
*
* manage admins.
* add admins here
* this will allow admins more control on all tables, but not accessing and managing users
* controlling, accessing and managing users is configured through:
* - config/web.php and views/layouts/main.php
* - (1) in config/web.php go to modules -> user -> admins and add username(s)that you want to be admin accessing and managing users
* - (2) THEN in view views/layouts/main.php, follow the same logic in line 62 and add username(s).
*
* #return bool
*/
public static function isAdmin()
{
if (
Yii::$app->user->identity->username == 'type user name here'
or
Yii::$app->user->identity->username == 'type user name here'
// add more here for example by uncommenting the following lines and typing username that you want to be admin
// or
// Yii::$app->user->identity->username == 'type user name here'
// or
// Yii::$app->user->identity->username == 'type user name here'
// or
// Yii::$app->user->identity->username == 'type user name here'
) {
return true;
} else {
return false;
}
}
}

Related

laravel DB update get changes column

i want to save log of changes when i update something on the database.
there is elegant way to get the column that will be updated (just if there is change).
i want to save the old column value in log..
for example:
$updateUser = DB::table('users')->where('id','1')->update(array('email' => 'new#email.com', 'name' => 'my new name'));
from this i want to get back the old email was in database (if changed) and the old name (again, only if changed)
thanks!
As others have mentioned, Eloquent is a great way to go if using Laravel. Then you can tap directly into Laravel's events using Observers. I have used a method very similar to what is below. Of course, you would need to set up Models for User and AuditLog.
See more info regarding Observers.
https://laravel.com/docs/5.8/eloquent#observers
In Controller Method
$user = User::find(1);
$user->update([
'email' => 'new#email.com',
'name' => 'my new name'
]);
App/Providers/EventServiceProvider.php
class EventServiceProvider extends ServiceProvider
{
// ...
public function boot()
{
User::observe(UserObserver::class);
}
}
App/Observers/UserObserver.php
class UserObserver
{
/**
* The attributes to exclude from logging.
*
* #var array
*/
protected $except = [
'created_at',
'updated_at'
];
/**
* The attributes to mask.
*
* #var array
*/
protected $masked = [
'password',
];
/**
* Listen for model saved event.
*
* #var array
*/
public function saved($model)
{
// search for changes
foreach ($model->getChanges() as $key => $new_value) {
// get original value
$old_value = $model->getOriginal($key);
// skip type NULL with empty fields
if ($old_value === '' && $new_value === null) {
continue;
}
// attribute not excluded and values are different
if (!in_array($key, $this->except) && $new_value !== $old_value) {
// mask designated fields
if (in_array($key, $this->masked)) {
$old_value = '********';
$new_value = '********';
}
// create audit log
AuditLog::create([
'user_id' => auth()->user()->id,
'model_id' => $model->id,
'model' => (new \ReflectionClass($model))->getShortName(),
'action' => 'update',
'environment' => config('app.env'),
'attribute' => $key,
'old_value' => $old_value,
'new_value' => $new_value,
]);
}
}
}
}
I hope this helps!
EDIT: See comment regarding update.
I will suggest 2 options:
1) to use the Eloquent model on every changes,
and then to use the existing methods like :
model->isDirty()
model->getChanges()
you can implement it on the model life cycle of updating / updated events listeners
more information and example you can see here:
https://laravel.com/docs/5.8/events
https://medium.com/#JinoAntony/10-hidden-laravel-eloquent-features-you-may-not-know-efc8ccc58d9e
https://laravel.com/api/5.3/Illuminate/Database/Eloquent/Model.html
2) if you want to log changes even if you are running regular queries and not only via model life cycle,
you can use MySql Triggers on every table updates and then to check OLD vs NEW and insert directly to the log changes db
more information you can find here:
https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
MySQL Trigger after update only if row has changed
Why not just something like this:
$changeArr = ['email' => 'new#email.com', 'name' => 'my new name'];
$id = 1;
$table = 'users';
foreach($changeArr as $key => $value){
DB::table('updateTable')->insert(['table' => $table, 'id' => $id, 'col' => $key, 'oldVal' => $value]);
}
$updateItem = DB::table($table)->where('id', $id)->update($changeArr);
Check for the changed values and update accordingly, saving the old values to log table if changed
$newData = ['email' => 'new#email.com', 'name' => 'my new name'];
$user = App\User::find(1);
$log = [];
if ($user->email != $newData['email']) {
$log['user_id'] = $user->id;
$log['email'] = $user->email;
$user->email = $newData['email'];
} elseif ($user->name != $newData['name']) {
$log['name'] = $user->name;
$user->name = $newData['name'];
$logged = DB::table('log')->insert($log);
}
$updateUser = $user->save();
//try this. hpe it helps out:
function Update(Request $request, $id)
{
$dbrecord = DB::table('users')->where('id',$id)->first();
$oldemail = $dbrecord->email;
$oldname = $dbrecord->name;
if(($oldemail==$request->input('email'))&&($oldname==$request->input('name')))
{
//do nothing
}
elseif(($oldemail!=$request->input('email'))or($oldname!=$request->input('name')))
{
$updateUser = DB::table('users')->where('id',$id)->update(array('email' => $request->input('email'), 'name' => $request->input('name')));
if($updateUser)
{
DB::table('log')->where('id',$id)->insert(array('email' => $oldemail, 'name' => $oldname));
}
}
}

Yii2 Kartik editable input value will only change after refresh

I use Kartik Editable input widget. I have a home model and tema model attribute here. Whenever I input and submit value in the field, the value won't change on-the spot but will only change after I refresh the page instead. What should I do? Thanks!
My controller :
public function actionIndex()
{
$searchModel = new HomeSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
// table only has one row
$model= Home::find()->one();
// Check if there is an Editable ajax request
if (isset($_POST['hasEditable'])) {
// use Yii's response format to encode output as JSON
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
// read your posted model attributes
if ($model->load($_POST)) {
// read or convert your posted information. Based on the 'name' property set in the view. So this 'tema' of $model-> tema comes from 'name' property set in the view.
$value = $model->tema;
$model->save();
// return JSON encoded output in the below format
return ['output'=>$value, 'message'=>'output berhasil'];
// alternatively you can return a validation error
// return ['output'=>'', 'message'=>'Validation error'];
}
// else if nothing to do always return an empty JSON encoded output
else {
return ['output'=>'', 'message'=>'output gagal'];
}
};
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'model'=>$model,
]);
}
The view
<?php
echo Editable::widget([
'model' => $model,
'attribute' => 'tema',
'value'=>$model->tema,
/*'asPopover'=>'false',*/
'type' => 'post',
'header'=>'tema',
'valueIfNull'=>'value-nya NULL',
'format'=>'link',
'size'=> 'lg',
'inputType' => Editable::INPUT_TEXT,
'editableValueOptions' => ['class' => 'text-success h3']
]); ?>
Another issue, whenever I used 'asPopover'=>'false', it shows no error but nothing happen when I click the supposedly editable-input field. The editable-inline field just won't show up. When I use the popOver option,the pop-up just automatically triggered without clicking and also it pop-up on the top left corner of the page. Only after I clicked on the editable widget that triggered the pop-up will it recorrect itself to the proper position. Is it a bug? I used the latest Yii2 with bootstrap 4, and I had set the global parameter in params.php config with 'bsVersion' => '4.x', as in the documentation
In the Controller, try this:
public function actionIndex()
{
$searchModel = new HomeSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
if (isset($_POST['hasEditable']))
{
$tema = Yii::$app->request->post('editableKey');
$modelHome = Home::findOne($tema);
$posted = current($_POST['Home']);
$post = ['Home' => $posted];
if ($modelHome->load($post)) {
$modelHome->save();
$out = Json::encode(['output'=>$modelHome->tema, 'message'=>'']);
return $out;
}
return;
};
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'model'=>$model,
]);
}

Drupal 8 custom module from with ajax and template override

I'm creating a module that has a custom admin 2-col page that uses ajax to populate a div, showing content based on a dropdown selection before form submission.
It all works fine, and I can see the container updated by ajax.
But when I try use a custom template for 2-col layout, I get the following inserted into the container:
An unrecoverable error occurred. The uploaded file likely exceeded the
maximum file size (50 MB) that this server supports.
There are no watchdog messages or log details, so this might suggest an apache configuration issue (https://www.drupal.org/forum/support/post-installation/2013-02-27/an-unrecoverable-error-occurred-the-uploaded-file-likely), but mod_security does not appear to be enabled, and the form does not contain any files and it's no way near 50MB! So I don't know where this is coming from. This is currently in my dev environment on my laptop and I've not faced this before, so I don't think apache config is an issue.
It strikes me that there may be a core bug in the form API for ajax with custom templates, because it works fine without a custom template... unless I'm implementing the custom template incorrectly.
A possible workaround would be to use CSS for force the container onto the RHS, but this should ideally be in the template so that admin themes can work with it.
I've put the code in pastebin: https://pastebin.com/F1zkd5rg.
or listed below:
my_module.links.menu.yml
my_module.main:
route_name: my_module.main
title: My Module
parent: system.admin
weight: -6
my_module.form_page:
route_name: my_module.form_page
title: My Module Form
parent: my_module.main
weight: -6
my_module.routing.yml
my_module.main:
path: '/admin/my_module'
defaults:
_controller: 'Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
_title: 'My Module'
requirements:
_permission: 'administrator'
my_module.form_page:
path: '/admin/my_module/form'
defaults:
_form: 'Drupal\my_module\Form\MyModuleForm'
_title: 'My Module Form'
requirements:
_permission: 'administrator'
my_module.module
<?php
/**
* Implements hook_theme_registry_alter
*/
function my_module_theme($existing, $type, $theme, $path) {
return [
'my_module_form' => [
'render element' => 'form',
],
];
}
templates/my-module-form.html.twig
<form {{ attributes }}>
<div class="layout-column layout-column--half">
{{ form.user_view }}
{{ form.submit }}
</div>
<div class="layout-column layout-column--half">
{{ form.user_list_wrapper }}
</div>
</form>
src/Form/MyModuleForm.php
<?php
/**
* #file
* Contains \Drupal\my_module\Form\MyModuleForm.
*/
namespace Drupal\my_module\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Views;
/**
* Configure custom_rest settings for this site.
*/
class MyModuleForm extends FormBase {
/**
* {#inheritdoc}
*/
public function getFormId() {
return 'my_module_form';
}
/**
* {#inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
...
$form['#theme'] = 'my_module_form';
$form['user_view'] = [
'#type' => 'select',
'#title' => $this->t('Select element'),
'#options' => $userViews,
'#ajax' => [
'callback' => '::findUsers',
'event' => 'change',
'wrapper' => 'edit-user-list',
'progress' => array(
'type' => 'throbber',
'message' => t('Searching Users...'),
),
],
];
$form['user_list_wrapper'] = [
'#type' => 'container',
'#attributes' => array(
'class' => array(
'user-list-wrapper',
),
),
];
$form['user_list_wrapper']['user_list'] = [
'#type' => 'item',
'#attributes' => [
'id' => ['user_list'],
],
'#markup' => '<ul><li>None</li></ul>'
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Submit'),
];
return $form;
}
/**
* Ajax callback to list users.
*/
public function findUsers(array &$form, FormStateInterface $form_state) {
// Create the user list HTML
$selected = $form_state->getValue('user_view');
...
$user_list = '';
...
if (strlen($user_list) == 0) {
$user_list = 'None';
} else {
$user_list = "<ul>$user_list</ul>";
}
// Generate the AJAX response
$ajax_response = new AjaxResponse();
$ajax_response->addCommand(new HtmlCommand('#edit-user-list', $user_list));
return $ajax_response;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
drupal_set_message('Nothing Submitted. Just an Example.');
}
}
Thanks in advance

Drupal 7 node_save() causes AJAX to fail

I've created custom node form with only two fields attached. Each field have own "Save" AJAX button. On "Save" button click, everything goes as if it is default node form submission. Here is the full code:
/**
* Form;
*/
function mymodule_custom_form($form, &$form_state) {
$node = node_load(123);
$node->langcode = entity_language('node', $node);
// Store node object in form state
if (!isset($form_state['node'])) {
if (!isset($node->title)) {
$node->title = NULL;
}
node_object_prepare($node);
$form_state['node'] = $node;
}
else {
$node = $form_state['node'];
}
// Basic node information.
// These elements are just values so they are not even sent to the client.
$properties = array('nid', 'vid', 'uid', 'created', 'type', 'language');
foreach ($properties as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => isset($node->$key) ? $node->$key : NULL,
);
}
// Changed must be sent to the client, for later overwrite error checking.
$form['changed'] = array(
'#type' => 'hidden',
'#default_value' => isset($node->changed) ? $node->changed : NULL,
);
// TEST 1 field
field_attach_form('node', $node, $form, $form_state, $node->langcode, array(
'field_name' => 'field_test_1'
));
// Set the form prefix and suffix to support AJAX
$form['field_test_1']['#prefix'] = '<div id="wrapper-field-test-1">';
$form['field_test_1']['#suffix'] = '</div>';
// the submit button
$form['field_test_1']['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#name' => 'button-field-test-1',
'#ajax' => array(
'callback' => 'mymodule_custom_form_ajax_submit',
'wrapper' => 'wrapper-field-test-1',
'method' => 'replace',
'effect' => 'fade',
)
);
// TEST 2 field
field_attach_form('node', $node, $form, $form_state, $node->langcode, array(
'field_name' => 'field_test_2'
));
// Set the form prefix and suffix to support AJAX
$form['field_test_2']['#prefix'] = '<div id="wrapper-field-test-2">';
$form['field_test_2']['#suffix'] = '</div>';
// the submit button
$form['field_test_2']['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#name' => 'button-field-test-2',
'#ajax' => array(
'callback' => 'mymodule_custom_form_ajax_submit',
'wrapper' => 'wrapper-field-test-2',
'method' => 'replace',
'effect' => 'fade',
)
);
return $form;
}
/**
* Form validate;
*/
function mymodule_custom_form_validate($form, &$form_state) {
$field_name = reset($form_state['triggering_element']['#parents']);
// Validate only the stuff we need
$fields = array(
'field_test_1',
'field_test_2'
);
foreach ($fields as $field => $bundle) {
if ($field_name != $field) {
unset($form_state['values'][$field], $form_state['input'][$field]);
}
}
// $form_state['node'] contains the actual entity being edited, but we must
// not update it with form values that have not yet been validated, so we
// create a pseudo-entity to use during validation.
$node = (object) $form_state['values'];
node_validate($node, $form, $form_state);
entity_form_field_validate('node', $form, $form_state);
}
/**
* Form submit;
*/
function mymodule_custom_form_submit($form, &$form_state) {
// Execute all submit functions
$node = $form_state['node'];
entity_form_submit_build_entity('node', $node, $form, $form_state);
node_submit($node);
foreach (module_implements('node_submit') as $module) {
$function = $module . '_node_submit';
$function($node, $form, $form_state);
}
// Save the node
node_save($node);
$form_state['values']['nid'] = $node->nid;
$form_state['nid'] = $node->nid;
}
/**
* Form ajax submit;
*/
function mymodule_custom_form_ajax_submit($form, &$form_state) {
$field_name = reset($form_state['triggering_element']['#parents']);
// validate the form
drupal_validate_form('mymodule_custom_form', $form, $form_state);
// if there are errors, return the form to display the error messages
if (form_get_errors()) {
$form_state['rebuild'] = TRUE;
return $form[$field_name];
}
// process the form
mymodule_custom_form_submit($form, $form_state);
// Show the processing box
$form[$field_name] = array('#markup' => 'Thanks!');
$form[$field_name]['#prefix'] = '<div id="wrapper-' . str_replace('_', '-', $field_name) . '">';
$form[$field_name]['#suffix'] = '</div>';
// return the confirmation message
return $form[$field_name];
}
The code works perfectly, except that node_save($node) causes The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved. error.
No errors, if I remove it. But I need to save node and trigger all the hooks.
I think the issue caused by this line :
// process the form
mymodule_custom_form_submit($form, $form_state);
in your ajax function, try to use the node_save into your ajax function. mymodule_custom_form_submit is the conventional hook usually used. It seems to be several save process at the same time.
I don't know if you've solved it or not, but I've been stuck in a similar situation.
I avoid the error: The content on this page has either been modified..., modifying changed value in $form_state. In your submit function: mymodule_custom_form_submit, right after node_save($node), Add this line:
$form_state['input']['changed'] = $node->changed;
Drupal 7 full Save & Stay callback function, please add wrapper for form:
function <MODULE_NAME>_node_ajax_save_callback($form, &$form_state){
// If error, return form.
if (form_get_errors()) {
return $form;
}
node_form_submit($form, $form_state);
$form['changed']['#value'] = $form_state['node']->changed;
return $form;
}

Why aren't validation errors being displayed in CakePHP?

I'm trying to perform validation in the login page for the name,email and password fields. If the input fails validation,the error message should be displayed.
But here,when I fill in the details and submit, it is redirected to the next page. Only the value is not saved in the database.
Why is the message not displayed?
This is my model:
class User extends AppModel {
var $name = 'User';
var $validate = array(
'name' => array(
'alphaNumeric' => array(
'rule' => 'alphaNumeric',
'required' => true,
'message' => 'Alphabets and numbers only'
),
'between' => array(
'rule' => array('between', 5, 15),
'message' => 'Between 5 to 15 characters'
)
),
'password' => array(
'rule' => array('minLength', '8'),
'message' => 'Mimimum 8 characters long'
),
'email_id' => 'email'
);
function loginUser($data) {
$this->data['User']['email_id'] = $data['User']['email_id'];
$this->data['User']['password'] = $data['User']['password'];
$login = $this->find('all');
foreach ($login as $form):
if ($this->data['User']['email_id'] == $form['User']['email_id'] && $this->data['User']['password'] == $form['User']['password']) {
$this->data['User']['id'] = $this->find('all',
array(
'fields' => array('User.id'),
'conditions' => array(
'User.email_id' => $this->data['User']['email_id'],
'User.password'=>$this->data['User']['password']
)
)
);
$userId=$this->data['User']['id'][0]['User']['id'];
return $userId;
}
endforeach;
}
function registerUser($data) {
if (!empty($data)) {
$this->data['User']['name'] = $data['User']['name'];
$this->data['User']['email_id'] = $data['User']['email_id'];
$this->data['User']['password'] = $data['User']['password'];
if($this->save($this->data)) {
$this->data['User']['id']= $this->find('all', array(
'fields' => array('User.id'),
'order' => 'User.id DESC'
));
$userId=$this->data['User']['id'][0]['User']['id'];
return $userId;
}
}
}
}
This is my controller:
class UsersController extends AppController {
var $name = 'Users';
var $uses=array('Form','User','Attribute','Result');
var $helpers=array('Html','Ajax','Javascript','Form');
function login() {
$userId = $this->User->loginUser($this->data);
if($userId>0) {
$this->Session->setFlash('Login Successful.');
$this->redirect('/forms/homepage/'.$userId);
break;
} else {
$this->flash('Login Unsuccessful.','/forms');
}
}
function register() {
$userId=$this->User->registerUser($this->data);
$this->Session->setFlash('You have been registered.');
$this->redirect('/forms/homepage/'.$userId);
}
}
EDIT
Why is the message,example,"Minimum 8 characters long", is not being displayed when give less than 8 characters in the password field?
<!--My view file File: /app/views/forms/index.ctp -->
<?php
echo $javascript->link('prototype.js');
echo $javascript->link('scriptaculous.js');
echo $html->css('main.css');
?>
<div id="appTitle">
<h2> formBuildr </h2>
</div>
<div id="register">
<h3>Register</h3>
<?php
echo $form->create('User',array('action'=>'register'));
echo $form->input('User.name');
echo $form->error('User.name','Name not found');
echo $form->input('User.email_id');
echo $form->error('User.email_id','Email does not match');
echo $form->input('User.password');
echo $form->end('Register');
?>
</div>
<div id="login">
<h3>Login</h3>
<?php
echo $form->create('User',array('action'=>'login'));
echo $form->input('User.email_id');
echo $form->input('User.password');
echo $form->end('Login');
?>
</div>
Your validation seems correct
How about trying the following:
Make sure set your $form->create to the appropriate function
Make sure there is no $this->Model->read() before issuing Model->save();
Edit
Did you have the following?:
function register()
{
//do not put any $this->User->read or find() here or before saving pls.
if ($this->User->save($this->data))
{
//...
}
}
Edit2
IF you're doing a read() or find() before saving the Model then that will reset the fields. You should be passing the variable as type=hidden in the form. I hope i am making sense.
Edit3
I think you need to move your registerUser() into your controller because having that function in the model doesn't provide you a false return. it's always going to be true even if it has validation errors.
Comment out the redirect line and set the debug to 2 in config/core.php. Then look at the sql that is being generated to see if your insert is working. If the errors are not being displayed, maybe in the view, you are using $form->text or $form->select instead of the $form->input functions. Only the $form->input functions will automatically display the error messages.

Resources