In Symfony4 update function not working,after values fetch from database - mysql

I'm new to Symfony.I made a form with
insert,delete,view,update. In view page i added a edit button which is used
to update the values.when i submit the form after change the values in form
values will not updated in output.Please share your thoughts.
Thank You...
here i attached my controller code
/**
* #Route("/update/{id}", name="update")
*/
//edit function
public function edit($id,Request $request,Ramsurath $ramsurath) :Response
{
$form = $this->createForm(RamsurathType::class, $ramsurath);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('index');
}
return $this->render('ramsurath/update.html.twig',
['ramsurath'=>$ramsurath,'form' => $form->createView()]);
}

See the Symfony Documentation for Processing Forms.
You are missing the call to $form->getData() before flushing:
/**
* #Route("/update/{id}", name="update")
*/
//edit function
public function edit($id,Request $request,Ramsurath $ramsurath) :Response
{
$form = $this->createForm(RamsurathType::class, $ramsurath);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$ramsurath = $form->getData(); // this is the line you are missing
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('index');
}
return $this->render('ramsurath/update.html.twig',
['ramsurath'=>$ramsurath,'form' => $form->createView(),
]);
}

Related

Validation error on custom model attributes not displayed in form

I have a model with the following custom attributes topic_names, topic_details (string fields). I have also a model form with the custom attributes and custom rules. When I insert wrong data in the form fields, there is a model error, but it isn't displayed.
Model code:
......
public function rules()
{
return [
...
[['topics_names','topics_details'],'string'],
[['topics_names'],'checkCorrectAndSetTopics'],
];
}
public function checkCorrectAndSetTopics(){
if($this->topics_names AND $this->topics_details){
$topicsNamesArray = explode(',',$this->topics_names);
$topicsDetailsArray = explode(';',$this->topics_details);
if(sizeof($topicsNamesArray) !== sizeof($topicsDetailsArray)){
$this->addError('topics_names', \Yii::t('app', 'The topics names and details sets have different sizes'));
return FALSE;
}
}
return TRUE;
}
The problem is when the second rules is violeted, the form doesn't show any error, but there is. I checked it debugging the code below.
Form code:
..........
<?php
ActiveForm::$autoIdPrefix = createRandomId();//Function which creates a random id
$form = ActiveForm::begin(
['enableAjaxValidation' => true, "options"=> ["class"=>"extra-form"]]);
?>
<?= $form->errorSummary($model); ?>
<?= $form->field($model, 'topics_names')->textInput()
->label(\Yii::t('app', 'Topics Names'))?>
<?= $form->field($model, 'topics_details')->textarea(['rows' => 6])
->label(\Yii::t('app', 'Topics Details'))?>
........
Controller code:
public function actionAddExtraData($id){
if(!Yii::$app->request->isAjax){
throw new ForbiddenHttpException(\Yii::t('app','Cannot access this action directly.'));
}
$event = $this->findModel($id);
$extraData = ExtraData::find()
->andWhere(['event_id'=>$id])
->one();
if(!$extraData){
$extraData = new ExtraData();
$extraData->event_id = $id;
}else{
$extraData->prePerformForm();//Insert data on custom attributes
}
if(Yii::$app->request->isPost AND Yii::$app->request->isAjax AND Yii::$app->request->post("submitting") != TRUE
AND $extraData->load(Yii::$app->request->post())){
Yii::$app->response->format = Response::FORMAT_JSON;
$validation = ActiveForm::validate($extraData);
return $validation;
}
if ($extraData->load(Yii::$app->request->post()) && $extraData->save()) {
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ["success" => TRUE];
} else {
return $this->redirect(Yii::$app->request->referrer);
}
}
return $this->renderAjax('_event_extra_form',['model'=>$extraData,'event'=>$event]);
}
First thing, pretty sure you don't need to return true or false, you just need to add error. Second thing, in your example you name the attribute, you can actually get this when defining the function, so your function could look something like this
public function checkCorrectAndSetTopics($attribute, $model){
if($this->topics_names AND $this->topics_details){
$topicsNamesArray = explode(',',$this->topics_names);
$topicsDetailsArray = explode(';',$this->topics_details);
if(sizeof($topicsNamesArray) !== sizeof($topicsDetailsArray)){
$this->addError($attribute, \Yii::t('app', 'The topics names and details sets have different sizes'));
}
}
}

Check if db row has specific values

I am creating an event, each event will have attendees, I got this working fine, the problem I am having is an attendee can attend the same event twice, which is not good.
Event View
<?php if($this->session->userdata('user_id')): ?>
<hr>
<?php echo form_open('/attendees/add/'.$event['id']); ?>
<input type="hidden" name="user_id" value="<?php echo $_SESSION['user_id']; ?>">
<input type="submit" value="I'm in!" class="btn btn-success">
</form>
<?php endif; ?>
Attendees Controller
<?php
class Attendees extends CI_Controller {
public function add($event_id) {
// Check login
if(!$this->session->userdata('logged_in')){
redirect('users/login');
}
$this->form_validation->set_rules('user_id', 'required|callback_check_userid_eventid');
if($this->form_validation->run() === FALSE){
$this->session->set_flashdata('attendee_not_added', 'You are already on the list.');
redirect('home');
} else {
$this->attendee_model->add_attendee($event_id);
// Set message
$this->session->set_flashdata('attendee_added', 'You have been added to this event.');
redirect('events');
}
}
}
Attendees Model
<?php
class Attendee_model extends CI_Model {
public function __contruct() {
}
public function get_attendees($id = FALSE){
if($id === FALSE) {
$query = $this->db->get('attendees');
return $query->result_array();
}
$this->db->select('attendees.id, attendees.team, attendees.is_goalie, event.id, user.first_name, user.last_name');
$this->db->from('attendees');
$this->db->join('event', 'attendees.event_id = event.id', 'inner');
$this->db->join('user', 'attendees.user_id = user.id', 'inner');
$this->db->where('event.id', $id);
$query = $this->db->get();
return $query->row_array();
}
public function add_attendee($event_id){
$data = array(
'event_id' => $event_id,
'user_id' => $this->session->userdata('user_id')
);
return $this->db->insert('attendees', $data);
}
// Check attendee exists in event
public function check_userid_eventid($event_id, $user_id){
$query = $this->db->get_where('attendees', array('user_id' => $user_id, 'event_id' => $event_id));
if(empty($query->row_array())){
return true;
} else {
return false;
}
}
}
As you can see I tried creating a custom callback on the button form validation but it did not work.
If anyone can point me in the right direction, let me know if I am even somewhat close.
Thanks in advance.
You are not passing the $event_id value to the callback function. Replace your validation with the following line
$this->form_validation->set_rules('user_id', 'User ID', 'required|callback_check_userid_eventid['.$event_id.']');
add following callback function inside the Attendees Controller file
public function check_userid_eventid($user_id, $event_id){
$CI =& get_instance();
$CI->load->database();
$CI->form_validation->set_message('user_id_unique', "Sorry, that %s is already being used.");
return isset($CI->db) ? ($CI->db->limit(1)->get_where('attendees',compact('user_id','event_id'))->num_rows() == 0) : false;
}
Your callback is in a model that form validation knows nothing about. If you look at the docs: callbacks should be in the same controller as the form validation method that uses it.
However, you can use a function in a model as a callback with a different syntax:
$this->form_validation->set_rules(
'username', 'Username',
array(
'required',
array($this->users_model, 'valid_username')
)
);
as documented here.
Finally, on a false return, you need to make sure that you are setting a message as seen in this example:
public function username_check($str)
{
if ($str == 'test')
{
$this->form_validation->set_message('username_check', 'The {field} field can not be the word "test"');
return FALSE;
}
else
{
return TRUE;
}
}
In conclusion: the documentation has all the answers.
Put the call back function into Controller
<?php
class Attendees extends CI_Controller {
public function add($event_id) {
// Check login
if(!$this->session->userdata('logged_in')){
redirect('users/login');
}
$this->form_validation->set_rules('user_id', 'required|callback_check_userid_eventid');
if($this->form_validation->run() === FALSE){
$this->session->set_flashdata('attendee_not_added', 'You are already on the list.');
redirect('home');
} else {
$this->attendee_model->add_attendee($event_id);
// Set message
$this->session->set_flashdata('attendee_added', 'You have been added to this event.');
redirect('events');
}
}
// Check attendee exists in event
public function check_userid_eventid($event_id, $user_id){
$query = $this->db->get_where('attendees', array('user_id' => $user_id, 'event_id' => $event_id));
if(empty($query->row_array())){
return true;
} else {
return false;
}
}
}

ZF2AuthAcl Module doesnt work out of the box

I picked up this ZF2AuthAcl module to make my life easier. For some reason it does not work out of the box. As soon as i activate it in Zend2 Application.config it takes over the whole site. Meaning it goes straight to login on any page i have. There is a "white list" and i tried to add pages to this in an array and it does not seem to work. I will show the Acl page that it has with the "white list" maybe i did not add them correctly or there is a better way. It is data driven also. Has anyone used this with success or know about it?
The author is the one who told me it probably has to do with the white list.
The area that i added to looked like this:
public function initAcl()
{
$this->roles = $this->_getAllRoles();
$this->resources = $this->_getAllResources();
$this->rolePermission = $this->_getRolePermissions();
// we are not putting these resource & permission in table bcz it is
// common to all user
$this->commonPermission = array(
'ZF2AuthAcl\Controller\Index' => array(
'logout',
'index'
),
);
$this->_addRoles()
->_addResources()
->_addRoleResources();
}
This is the whole thing with parts i added.
namespace ZF2AuthAcl\Utility;
use Zend\Permissions\Acl\Acl as ZendAcl;
use Zend\Permissions\Acl\Role\GenericRole as Role;
use Zend\Permissions\Acl\Resource\GenericResource as Resource;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Acl extends ZendAcl implements ServiceLocatorAwareInterface
{
const DEFAULT_ROLE = 'guest';
protected $_roleTableObject;
protected $serviceLocator;
protected $roles;
protected $permissions;
protected $resources;
protected $rolePermission;
protected $commonPermission;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
public function initAcl()
{
$this->roles = $this->_getAllRoles();
$this->resources = $this->_getAllResources();
$this->rolePermission = $this->_getRolePermissions();
// we are not putting these resource & permission in table bcz it is
// common to all user
$this->commonPermission = array(
'ZF2AuthAcl\Controller\Index' => array(
'logout',
'index'
),
'Frontend\Controller\Index' => array(
'index'
),
'Blog\Controller\Blog' => array(
'blog',
'list',
'view',
'UsMap',
'maps'
)
);
$this->_addRoles()
->_addResources()
->_addRoleResources();
}
public function isAccessAllowed($role, $resource, $permission)
{
if (! $this->hasResource($resource)) {
return false;
}
if ($this->isAllowed($role, $resource, $permission)) {
return true;
}
return false;
}
protected function _addRoles()
{
$this->addRole(new Role(self::DEFAULT_ROLE));
if (! empty($this->roles)) {
foreach ($this->roles as $role) {
$roleName = $role['role_name'];
if (! $this->hasRole($roleName)) {
$this->addRole(new Role($roleName), self::DEFAULT_ROLE);
}
}
}
return $this;
}
protected function _addResources()
{
if (! empty($this->resources)) {
foreach ($this->resources as $resource) {
if (! $this->hasResource($resource['resource_name'])) {
$this->addResource(new Resource($resource['resource_name']));
}
}
}
// add common resources
if (! empty($this->commonPermission)) {
foreach ($this->commonPermission as $resource => $permissions) {
if (! $this->hasResource($resource)) {
$this->addResource(new Resource($resource));
}
}
}
return $this;
}
protected function _addRoleResources()
{
// allow common resource/permission to guest user
if (! empty($this->commonPermission)) {
foreach ($this->commonPermission as $resource => $permissions) {
foreach ($permissions as $permission) {
$this->allow(self::DEFAULT_ROLE, $resource, $permission);
}
}
}
if (! empty($this->rolePermission)) {
foreach ($this->rolePermission as $rolePermissions) {
$this->allow($rolePermissions['role_name'], $rolePermissions['resource_name'], $rolePermissions['permission_name']);
}
}
return $this;
}
protected function _getAllRoles()
{
$roleTable = $this->getServiceLocator()->get("RoleTable");
return $roleTable->getUserRoles();
}
protected function _getAllResources()
{
$resourceTable = $this->getServiceLocator()->get("ResourceTable");
return $resourceTable->getAllResources();
}
protected function _getRolePermissions()
{
$rolePermissionTable = $this->getServiceLocator()->get("RolePermissionTable");
return $rolePermissionTable->getRolePermissions();
}
private function debugAcl($role, $resource, $permission)
{
echo 'Role:-' . $role . '==>' . $resource . '\\' . $permission . '<br/>';
}
}
06/10/2016 Additional information
I have also found that this ACL page is not in any of the pages in the module. The functions are not called out anywhere in any page nor is it "use" on any page. So how is it supposed to work?
Update 06/10/2017 - Area that has been fixed.
I have found where this is used in the module.php there is a whitelist that the pages have to be added too. Below is where you add them.
$whiteList = array(
'Frontend\Controller\Index-index',
*Add whatever modules/controller/action you do not want included*
'ZF2AuthAcl\Controller\Index-index',
'ZF2AuthAcl\Controller\Index-logout'
);
Above is the conclusion of my issue. I stumbled upon it. I did not look in the module.php file. That is where the answer was.
Here is a general implementation of Zend ACL. I followed this one. If you wish you can follow this one too.
Create a file named module.acl.php in the config/ folder of your module. This file contains configuration for roles and permissions. Modify this script as you need.
ModuleName/config/module.acl.php
return array(
'roles' => array(
'guest',
'member'
),
'permissions' => array(
'guest' => array(
// Names of routes for guest role
'users-signup',
'users-login'
),
'member' => array(
// Names of routes for member role
// Add more here if you need
'users-logout'
)
)
);
You need to import the following three classes and define and initialize some methods in the Module.php.
ModuleName/Module.php
use Zend\Permissions\Acl\Acl;
use Zend\Permissions\Acl\Role\GenericRole;
use Zend\Permissions\Acl\Resource\GenericResource;
// Optional; use this for authentication
use Zend\Authentication\AuthenticationService;
Now lets create methods that will deploy ACL and check roles and permissions.
Module::initAcl()
public function initAcl(MvcEvent $e)
{
// Set the ACL
if ($e->getViewModel()->acl == null) {
$acl = new Acl();
} else {
$acl = $e->getViewModel()->acl;
}
// Get the roles and permissions configuration
// You may fetch configuration from database instead.
$aclConfig = include __DIR__ . '/config/module.acl.php';
// Set roles
foreach ($aclConfig['roles'] as $role) {
if (!$acl->hasRole($role)) {
$role = new GenericRole($role);
$acl->addRole($role);
} else {
$role = $acl->getRole($role);
}
// Set resources
if (array_key_exists($role->getRoleId(), $aclConfig['permissions'])) {
foreach ($aclConfig['permissions'][$role->getRoleId()] as $resource) {
if (!$acl->hasResource($resource)) {
$acl->addResource(new GenericResource($resource));
}
// Add role to a specific resource
$acl->allow($role, $resource);
}
}
}
// Assign the fully prepared ACL object
$e->getViewModel()->acl = $acl;
}
Module::checkAcl()
public function checkAcl(MvcEvent $e) {
// Get the route
$route = $e->getRouteMatch()->getMatchedRouteName();
// Use this if you have authentication set
// Otherwise, take this off
$auth = new AuthenticationService();
// Set role as you need
$userRole = 'guest';
// Use this if you have authentication set
// Otherwise, take this off
if ($auth->hasIdentity()) {
$userRole = 'member';
$loggedInUser = $auth->getIdentity();
$e->getViewModel()->loggedInUser = $loggedInUser;
}
// Check if the resource has right permission
if (!$e->getViewModel()->acl->isAllowed($userRole, $route)) {
$response = $e->getResponse();
// Redirect to specific route
$response->getHeaders()->addHeaderLine('Location', $e->getRequest()->getBaseUrl() . '/404');
$response->setStatusCode(404);
return;
}
}
Now call those above methods on the onBootstrap() method in your Module.php. Initialize Module::initAcl() and check resource permission by adding Module::checkAcl() to the route event.
Module::onBootstrap()
public function onBootstrap(MvcEvent $e)
{
$this->initAcl($e);
$e->getApplication()->getEventManager()->attach('route', array($this, 'checkAcl'));
}
Let us know it helps you or not!

How to use Yii 2 Lajax ToggleTranslate

I searched in documentation how to turn on ToggleTranslate on Yii 2 but with no success. I echoed widget
<?= \lajax\translatemanager\widgets\ToggleTranslate::widget(); ?>
but it does not apper. Then I went to source code and got this:
if (!Yii::$app->session->has(Module::SESSION_KEY_ENABLE_TRANSLATE)) {
return;
}
I commented it and my button appeared. But button is not working. So my question is how to properly (by proper flow, by proper guide) configure it and run it?
Site controller I modified:
public function actionLogin()
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
/** set session key for appearing translate button */
if(array_key_exists('admin', Yii::$app->authManager->getAssignments(Yii::$app->user->id)))
\Yii::$app->session->set('frontendTranslation_EnableTranslate',1);
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}

Yii2 Dynamic Form update Action is not working

I like to explain my problem clearly,
Am using wbraganca/yii2-dynamicform
Here create action is working perfectly, but in update action
In the code which i marked, i don't know what i need to do, i dont have such field (addresses) in customer table. am stuck on that.
suppose if i create a variable in model like public $addressess, it makes me the reload the table again, and that cause while update the same form, data's getting reload and form viewing as empty without empty,
if create a function on that name, i don't know what to write on that..
Am simply using code like this
public function getaddressess()
{
}
Create Action Code
public function actionCreate()
{
$modelCustomer = new Customer;
$modelsAddress = [new Address];
if ($modelCustomer->load(Yii::$app->request->post())) {
$modelsAddress = Model::createMultiple(Address::classname());
Model::loadMultiple($modelsAddress, Yii::$app->request->post());
// ajax validation
if (Yii::$app->request->isAjax) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ArrayHelper::merge(
ActiveForm::validateMultiple($modelsAddress),
ActiveForm::validate($modelCustomer)
);
}
// validate all models
$valid = $modelCustomer->validate();
$valid = Model::validateMultiple($modelsAddress) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $modelCustomer->save(false)) {
foreach ($modelsAddress as $modelAddress) {
$modelAddress->customer_id = $modelCustomer->id;
if (! ($flag = $modelAddress->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $modelCustomer->id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('create', [
'modelCustomer' => $modelCustomer,
'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
]);
}
Help me to sort out this problem
$modelsAddress=$modelCustomer->addresses in that example mean array of related Address() instances
public function actionCreate()
{
$modelCustomer = new Customer;
$modelsAddress = $this->getaddressess($modelCustomer->id);
//...................
}
public function getaddressess($id)
{
$model = Address::find()->where(['id' => $id])->all();
return $model;
}
from
public function getaddressess($id)
{
$model = Address::find()->where(['id' => $id])->all();
return $model;
}
Shared above you will also need to add
on your Update view file :
'model' => $model,
'modelsAddress'=>$modelsAddress,
Hope this helps. It worked for me
It should be getAddresses() instead of getaddresses() (although both could work, I'd go with the first one to meet conventions). Or you could set a public $addresses if you don't need extra encapsulation.
suppose if i create a variable in model like public $addressess, it makes me the reload the table again, and that cause while update the same form, data's getting reload and form viewing as empty without empty,
I think you have a validation issue - no validator to mark the field as safe and you see it as empty after posting.
Add public $addresses to your Customer model.
Add "addresses" to your validation rules as safe (or more appropriate validator). This way after posting the form, it probably won't render empty.
This line code ---> $modelsAddress = $modelCustomer->addresses;
is get from model for customer at line ---> public function getAddresses()
this public function line code is code for get array related table from active record method on yii2.
$modelCustomer->addresses the word addresses should come from the $modelCustomer model you must have a relationship to the other table where you add the multiple values. In my example described in the video I have two tables po table and po_items table po_items table has foreign key of po_id. So when you make the Models using gii you will get a relationship in the model that is what you have to use instead of the addresses.
the relationship according my database should be - poItems you will see this at line 14
Add this to Customer Model
public function getAddresses(){
return $this->hasMany(Address::className(), ['id' => 'id']);
}
enter image description hereIn Po.php models:
public function getPoItems()
{
return $this->hasMany(PoItem::className(), ['po_id' => 'id']);
}
In PoController.php
public function actionUpdate($id)
{
$model = $this->findModel($id);
//$modelsPoItem = [new PoItem];
$modelsPoItem = $model->poItems;
if ($model->load(Yii::$app->request->post()) && $model->save())
{
$oldIDs = ArrayHelper::map($modelsPoItem, 'id', 'id');
$modelsPoItem = Model::createMultiple(PoItem::classname(), $modelsPoItem);
Model::loadMultiple($modelsPoItem, Yii::$app->request->post());
$deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsPoItem, 'id', 'id')));
// validate all models
$valid = $model->validate();
$valid = Model::validateMultiple($modelsPoItem) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $model->save(false)) {
if (! empty($deletedIDs))
{
PoItem::deleteAll(['id' => $deletedIDs]);
}
foreach ($modelsPoItem as $modelPoItem)
{
$modelPoItem->po_id = $model->id;
if (! ($flag = $modelPoItem->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('update', [
'model' => $model,
'modelsPoItem' => (empty($modelsPoItem)) ? [new PoItem] : $modelsPoItem
]);
}