Yii2 Dynamic forms action update get error - php

I have two models in my Yii2 application :
Racks(rackID,rowID,...)
RackObjects(rack_objectID,rackID,objectID,...)
In my racksController I have :
public function actionUpdate($id)
{
$model = $this->findModel($id);
$modelsRackObjects = $model->rackObjects;
if ($model->load(Yii::$app->request->post())) {
$oldIDs = ArrayHelper::map($modelsRackObjects, 'rack_objectID', 'rack_objectID');
$modelsRackObjects = Racks::createMultiple(RackObjects::classname(), $modelsRackObjects);
Racks::loadMultiple($modelsRackObjects, Yii::$app->request->post());
$deletedIDs = array_diff($oldIDs, array_filter(ArrayHelper::map($modelsRackObjects, 'rack_objectID', 'rack_objectID')));
// validate all models
$valid = $model->validate();
$valid = Racks::validateMultiple($modelsRackObjects) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $model->save(false)) {
if (!empty($deletedIDs)) {
Racks::deleteAll(['rackID' => $deletedIDs]);
}
foreach ($modelsRackObjects as $modelRackObjects) {
$modelRackObjects->rackID = $model->rackID;
if (! ($flag = $modelRackObjects->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $model->rackID]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('update', [
'model' => $model,
'modelsRackObjects' => (empty($modelsRackObjects)) ? [new RackObjects] : $modelsRackObjects
]);
}
And in my "Racks Model" I have :
public static function createMultiple($modelClass, $multipleModels = [])
{
$model = new $modelClass;
$formName = $model->formName();
$post = Yii::$app->request->post($formName);
$models = [];
if (! empty($multipleModels)) {
$keys = array_keys(ArrayHelper::map($multipleModels, 'rack_objectID', 'rack_objectID'));
$multipleModels = array_combine($keys, $multipleModels);
}
if ($post && is_array($post)) {
foreach ($post as $i => $item) {
if (isset($item['rack_objectID']) && !empty($item['rack_objectID']) && isset($multipleModels[$item['rack_objectID']])) {
$models[] = $multipleModels[$item['rack_objectID']];
} else {
$models[] = new $modelClass;
}
}
}
unset($model, $formName, $post);
return $models;
}
When I update the racks form and change some rackObjects I get this error :
Integrity constraint violation – yii\db\IntegrityException
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails
What is wrong in my action update???
I changed my codes thanks to this answer and now when I update records the child table (rackObjects) duplicated and old records was not deleted!! any idea?

deleteAll() will not raise the beforeDelete event. You should loop through:
$racks = Rack::findAll(['rackID' => $deletedIDs]);
foreach($racks as $rack) {
$rack->delete();
}
And in Rack model, assuming you have hasMany relationship with RackObjects
public function beforeDelete() {
if (parent::beforeDelete()) {
foreach($this->rackObjects as $rackObj) {
$rackObj->delete();
}
return true;
} else {
return false;
}
}

Related

How to add laravel query function lists in updateOrCreate eloquent

I am trying to use updateOrCreate with multiple conditions and this condition can be applied occasionally if corresponding data are available. I am currently doing as first find the id if exists and if id exists update else create manually but now i want to use laravel given updateOrCreate function.
$existing = Student::where('name_last', $student['name_last'])
->where('name_first', $student['name_first'])
->where(function($query) use ($student) {
if (array_key_exists('phone_preferred', $student) && !empty($student['phone_preferred'])) {
$query->where('phone_preferred', $student['phone_preferred']);
}
if (array_key_exists('email_preferred', $student) && !empty($student['email_preferred'])) {
$query->where('email_preferred', $student['email_preferred']);
}
if (array_key_exists('home_street_address_1', $student) && !empty($student['home_street_address_1'])) {
$query->where('home_street_address_1', $student['home_street_address_1']);
}
if (array_key_exists('mailing_street_address_1', $student) && !empty($student['mailing_street_address_1'])) {
$query->where('mailing_street_address_1', $student['mailing_street_address_1']);
}
if (array_key_exists('mailing_address_city', $student) && !empty($student['mailing_address_city'])) {
$query->where('mailing_address_city', $student['mailing_address_city']);
}
})->first();
if($existing){
try{
Student::where('id', $existing->id)
->update($student);
} catch (\Exception $e) {
$error_encountered = true;
$error_arr[] = $e->getMessage();
$error_row_numbers[] = $row_no;
}
}
I want to implement with something like:
try{
Student::updateOrCreate(
['name_first' => $student['name_first], 'name_last' => $student['name_last]],
$student
); //I could not get how to implement other occasional where condition
} catch (\Exception $e) {
$error_encountered = true;
$error_arr[] = $e->getMessage();
$error_row_numbers[] = $row_no;
}
I want to include those occasional where function query to updateOrCreate method which is currently implementing in manual method
You can just add all the attributes you want to check for in the array that you pass to updateOrCreate
// these are your required conditions
$conditions = [
'name_first' => $student['name_first'],
'name_last' => $student['name_last'],
];
// these are optional
$attributes = [
'phone_preferred',
'email_preferred',
'home_street_address_1',
'mailing_street_address_1',
'mailing_address_city'
];
foreach($attributes as $attr){
// check to see if the attribute exists on the student
// and is not empty
if(isset($student[$attr]) && !empty($student[$attr])){
$conditions[$attr] = $student[$attr];
}
}
Student::updateOrCreate($conditions);

Moodle: Error on form submission in activity module

Below is a sample of the code that I'm using for the form and then the handling og the file saving. There's something that I'm doing wrong, but I'm not sure what it is. Please assist. I have attached a screenshot showing the error that I'm getting after submitting the form.
error on form submission in moodle inside activity module
class mod_audio_mod_form extends moodleform_mod {
/**
* Defines forms elements
*/
public function definition() {
global $CFG;
$mform = $this->_form;
// Adding the "general" fieldset, where all the common settings are showed.
$mform->addElement('header', 'general', get_string('general', 'form'));
// Adding the standard "name" field.
$mform->addElement('text', 'name', get_string('audioname', 'audio'), array('size' => '64'));
if (!empty($CFG->formatstringstriptags)) {
$mform->setType('name', PARAM_TEXT);
} else {
$mform->setType('name', PARAM_CLEANHTML);
}
$mform->addRule('name', null, 'required', null, 'client');
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->addHelpButton('name', 'audioname', 'audio');
// Adding the standard "intro" and "introformat" fields.
if ($CFG->branch >= 29) {
$this->standard_intro_elements();
} else {
$this->add_intro_editor();
}
// Adding the rest of audio settings, spreading all them into this fieldset
// ... or adding more fieldsets ('header' elements) if needed for better logic.
$mform->addElement('header', 'audiofieldset', get_string('audiofieldset', 'audio'));
$filemanager_options = array();
$filemanager_options['accepted_types'] = '*';
$filemanager_options['maxbytes'] = 0;
$filemanager_options['maxfiles'] = -1;
$filemanager_options['mainfile'] = true;
$mform->addElement('filemanager', 'files', get_string('selectfiles'), null, $filemanager_options);
$mform->addRule('files', null, 'required', null, 'client');
// Add standard grading elements.
$this->standard_grading_coursemodule_elements();
// Add standard elements, common to all modules.
$this->standard_coursemodule_elements();
// Add standard buttons, common to all modules.
$this->add_action_buttons();
}
function data_preprocessing(&$default_values) {
if ($this->current->instance) {
// editing existing instance - copy existing files into draft area
$draftitemid = file_get_submitted_draft_itemid('files');
file_prepare_draft_area($draftitemid, $this->context->id, 'mod_audio', 'content', 0, array('subdirs' => true));
$default_values['files'] = $draftitemid;
}
}
function definition_after_data() {
if ($this->current->instance and $this->current->tobemigrated) {
// resource not migrated yet
return;
}
parent::definition_after_data();
}
function validation($data, $files) {
global $USER;
$errors = parent::validation($data, $files);
$usercontext = context_user::instance($USER->id);
$fs = get_file_storage();
if (!$files = $fs->get_area_files($usercontext->id, 'user', 'draft', $data['files'], 'sortorder, id', false)) {
$errors['files'] = get_string('required');
return $errors;
}
if (count($files) == 1) {
// no need to select main file if only one picked
return $errors;
} else if (count($files) > 1) {
$mainfile = false;
foreach ($files as $file) {
if ($file->get_sortorder() == 1) {
$mainfile = true;
break;
}
}
// set a default main file
if (!$mainfile) {
$file = reset($files);
file_set_sortorder($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename(), 1);
}
}
return $errors;
}
}
// THE CLASS IN LOCALLIB.PHP
class audio_content_file_info extends file_info_stored {
public function get_parent() {
if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') {
return $this->browser->get_file_info($this->context);
}
return parent::get_parent();
}
public function get_visible_name() {
if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') {
return $this->topvisiblename;
}
return parent::get_visible_name();
}
function save_files($data) {
global $DB;
// Storage of files from the filemanager (videos).
$draftitemid = $data->files;
if ($draftitemid) {
file_save_draft_area_files(
$draftitemid, $this->context->id, 'mod_audio', 'files', 0
);
}
}
}
// FUNCTION THAT ADDS THE INSTANCE IN LIB.PHP
function audio_add_instance(stdClass $audio, mod_audio_mod_form $mform = null) {
global $CFG, $DB;
require_once("$CFG->libdir/resourcelib.php");
require_once("$CFG->dirroot/mod/audio/locallib.php");
$cmid = $audio->coursemodule;
$audio->timecreated = time();
$audio->timemodified = time();
resource_set_display_options($audio);
$audio->id = $DB->insert_record('audio', $audio);
$context = context_module::instance($audio->coursemodule);
$audiofile = new audio_content_file_info($context, null, null);
$audiofile->save_files($audio);
// we need to use context now, so we need to make sure all needed info is already in db
$DB->set_field('course_modules', 'instance', $audio->id, array('id' => $cmid));
resource_set_mainfile($audio);
return $audio->id;
}
Please advice on what I could be doing wrong here.

2 table in 1 form Laravel

I had 2 tables . driver and part_time_available, when I select driver type parttime it'll show part_time_available field. the problem is I can't save.
it throws this error : Integrity constraint violation: 1048 Column 'driver_id' cannot be null
here's my save controller code so far :
public function save(Request $request, $obj = null) {
if (!$obj) {
$obj = new Driver;
}
$obj->active = TRUE;
$obj->counter = 0;
return $this->saveHandler($request, $obj);
}
public function saveHandler(Request $request, $obj)
{
try {
DB::beginTransaction();
$obj->fill($request->all());
if (!$obj->save()) {
throw new ValidationException($obj->errors());
}
foreach($request->parttimeAvailabilities as $pta) {
if (empty($pta['id'])) {
$parttimeAvailability = new ParttimeAvailability();
}
else {
$parttimeAvailability = ParttimeAvailability::find($pta['id']);
}
$parttimeAvailability->Driver()->associate($obj);
$pta['driver_id'] = isset($pta['driver_id']) ? $pta['driver_id'] : null;
$driver = Driver::find($pta['driver_id']);
$parttimeAvailability->driver()->associate($driver);
$parttimeAvailability->day = $pta['day'];
$parttimeAvailability->start_time = $pta['start_time'];
$parttimeAvailability->end_time = $pta['end_time'];
$parttimeAvailability->available = isset($pta['available']);
$parttimeAvailability->save();
};
$obj->save();
if (!$parttimeAvailability->save()) {
throw new ValidationException($parttimeAvailability->errors());
}
DB::commit();
return $this->sendSuccessResponse($request);
} catch (ValidationException $e) {
DB::rollback();
\Log::error($e->errors);
return $this->sendErrorResponse($request, $e->errors);
} catch (Exception $e) {
DB::rollback();
\Log::error($e->getMessage());
return $this->sendErrorResponse($request,'Unable to process. Please contact system Administrator');
}
}
any idea ??
Take a look here:
$pta['driver_id'] = isset($pta['driver_id']) ? $pta['driver_id'] : null;
$driver = Driver::find($pta['driver_id']);
From this code chunk we can see that driver_id can be null. In that case there is no driver to find. You should only search for a driver if you have an id.

Trying to get property of non-object. Laravel 5.2

I have problem when I'm trying to check if user has role in database. When I do it outside the model it works fine but for some reason when I need to do it in model I get "Trying to get property of non-object" error. Here is my code:
public function owed_amount() {
$user_total = $this->total_expenses();
$expenses = Expense::where('removed', false)->get();
$total = 0;
foreach ($expenses as $expense) {
$total += $expense->amount;
}
$total_users = 0;
$users = User::get();
foreach ($users as $user) {
if($user->has_role('is-payee')) //Error comes from here!
{
$total_users++;
}
}
$paid_in = $this->total_paid_in();
$got_paid = $this->total_got_paid();
$owed = $user_total - $total/$total_users + $paid_in - $got_paid;
return number_format($owed, 2);
}
public function has_role($data) { //Checking for role in database
$perm = Permission::where('data', $data)->first();
$ptg = PermissionToGroup::where([
'group_id' => $this->usergroup->id,
'perm_id' => $perm->id
])->first();
if($ptg===NULL){ return false; }
else{ return true; }
}
Cheers for your help!
You have to check if there is a result for $perm
public function has_role($data) { //Checking for role in database
$perm = Permission::where('data', $data)->first();
if($perm) {
$ptg = PermissionToGroup::where([
'group_id' => $this->usergroup->id,
'perm_id' => $perm->id
])->first();
if($ptg===NULL){ return false; }
else{ return true; }
}
else
return false;
}

save form field in component params joomla

I am using joomla 2.5, I am working on custom component of joomla . I have created the form in backend admin page. what i need is , i want to save the post data of form in params row of that component in database of #_extensions.
Here is my tables/component.php
<?php defined('_JEXEC') or die('Restricted access');
jimport('joomla.database.table');
class componentTablecomponent extends JTable {
function __construct(&$db)
{
parent::__construct('#__extensions', 'extension_id', $db);
}
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
// Convert the params field to a string.
$parameter = new JRegistry;
$parameter->loadArray($array['params']);
$array['params'] = (string)$parameter;
}
return parent::bind($array, $ignore);
}
public function load($pk = null, $reset = true)
{
if (parent::load($pk, $reset))
{
// Convert the params field to a registry.
$params = new JRegistry;
$params->loadJSON($this->params);
$this->params = $params;
return true;
}
else
{
return false;
}
} public function store() {
parent::store(null);
}
}
Instead of saving the $data in params row of that component . This code is creating new empty rows in that table(data is saving in those params field).
Here is my save() function in controllers/component.php
public function save()
{
// Check for request forgeries.
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
// Check if the user is authorized to do this.
if (!JFactory::getUser()->authorise('core.admin'))
{
`JFactory::getApplication()->redirect('index.php',JText::_('JERROR_ALERTNOAUTHOR'));`
return;
}
// Initialise variables.
$app = JFactory::getApplication();
$model = $this->getModel('component');
$form = $model->getForm();
$data = JRequest::getVar('jform', array(), 'post', 'array');
print_r($data);
// Validate the posted data.
$return = $model->validate($form, $data);
// Check for validation errors.
if ($return === false)
{
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof Exception) {
$app->enqueueMessage($errors[$i]->getMessage(), 'warning');
} else {
$app->enqueueMessage($errors[$i], 'warning');
}
}
// Redirect back to the edit screen.
$this->setRedirect(JRoute::_('somelink',false));
return false;
}
// Attempt to save the configuration.
$data = $return;
$return = $model->save($data);
// Check the return value.
if ($return === false)
{
// Save failed, go back to the screen and display a notice.
$message = JText::sprintf('JERROR_SAVE_FAILED', $model->getError());
$this->setRedirect('index.php/somelink','error');
return false;
}
// Set the success message.
$message = JText::_('COM_CONFIG_SAVE_SUCCESS');
// Set the redirect based on the task.
switch ($this->getTask())
{
case 'apply':
$this->setRedirect('somelink',$message);
break;
case 'cancel':
case 'save':
default:
$this->setRedirect('index.php', $message);
break;
}
return true;
}
models/component.php
public function save($data) {
parent::save($data);
return true;
}
I thinks these codes are enough . I can add more codes if you need.
If you want to store params in the extension table, why not just use com_config for it?
See http://docs.joomla.org/J2.5:Developing_a_MVC_Component/Adding_configuration
Then you don't have to do anything besides creating the config.xml and adding a link to the config options in the toolbar.
I have come up with a solution . it works for me . By using this method you can control save () functions i.e. you can run your custom php scripts on save, apply toolbar buttons.
I copied save(),save($data), store($updateNulls = false) functions from com_config component , I have copied the layout from component view . Removed the buttons. Added toolbar buttons in .html.php file.
controllers/mycomponent.php
<?php
defined('_JEXEC') or die;
class componentControllermycomponent extends JControllerLegacy {
function __construct($config = array())
{
parent::__construct($config);
// Map the apply task to the save method.
$this->registerTask('apply', 'save');
}
function save()
{
// Check for request forgeries.
JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));
// Set FTP credentials, if given.
JClientHelper::setCredentialsFromRequest('ftp');
// Initialise variables.
$app = JFactory::getApplication();
$model = $this->getModel('mymodel');
$form = $model->getForm();
$data = JRequest::getVar('jform', array(), 'post', 'array');
$id = JRequest::getInt('id');
$option = 'com_mycomponent';
// Check if the user is authorized to do this.
if (!JFactory::getUser()->authorise('core.admin', $option))
{
JFactory::getApplication()->redirect('index.php', JText::_('JERROR_ALERTNOAUTHOR'));
return;
}
// Validate the posted data.
$return = $model->validate($form, $data);
// Check for validation errors.
if ($return === false) {
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof Exception) {
$app->enqueueMessage($errors[$i]->getMessage(), 'warning');
} else {
$app->enqueueMessage($errors[$i], 'warning');
}
}
// Save the data in the session.
$app->setUserState('com_iflychat.config.global.data', $data);
// Redirect back to the edit screen.
$this->setRedirect(JRoute::_('index.php?option=com_mycomponent&view=component&component='.$option.'&tmpl=component', false));
return false;
}
// Attempt to save the configuration.
$data = array(
'params' => $return,
'id' => $id,
'option' => $option
);
// print_r($data);
$return = $model->save($data);
// Check the return value.
if ($return === false)
{
// Save the data in the session.
$app->setUserState('com_config.config.global.data', $data);
// Save failed, go back to the screen and display a notice.
$message = JText::sprintf('JERROR_SAVE_FAILED', $model->getError());
$this->setRedirect('index.php?option=com_mycomponent&view=component&component='.$option.'&tmpl=component', $message, 'error');
return false;
}
// Set the redirect based on the task.
switch ($this->getTask())
{
case 'apply':
$message = JText::_('COM_MYCOMPONENT_SAVE_SUCCESS');
print_r($data);
$this->setRedirect('index.php?option=com_mycomponent&view=myview&layout=edit', $message);
break;
case 'save':
default:
$this->setRedirect('index.php');
break;
}
return true;
}
function cancel()
{
$this->setRedirect('index.php');
}
}
models/mymodel.php
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.modelform');
class componentModelmymodel extends JModelForm {
protected $event_before_save = 'onConfigurationBeforeSave';
protected $event_after_save = 'onConfigurationAfterSave';
public function getForm($data = array(), $loadData = true){
// Get the form.
$form = $this->loadForm('com_mycomponent.form', 'config',
array('control' => 'jform', 'load_data' => $loadData));
if (empty($form)){
return false;
}
return $form;
}
public function save($data)
{
$dispatcher = JDispatcher::getInstance();
$table = JTable::getInstance('extension');
$isNew = true;
// Save the rules.
if (isset($data['params']) && isset($data['params']['rules']))
{
$rules = new JAccessRules($data['params']['rules']);
$asset = JTable::getInstance('asset');
if (!$asset->loadByName($data['option']))
{
$root = JTable::getInstance('asset');
$root->loadByName('root.1');
$asset->name = $data['option'];
$asset->title = $data['option'];
$asset->setLocation($root->id, 'last-child');
}
$asset->rules = (string) $rules;
if (!$asset->check() || !$asset->store())
{
$this->setError($asset->getError());
return false;
}
// We don't need this anymore
unset($data['option']);
unset($data['params']['rules']);
}
// Load the previous Data
if (!$table->load($data['id']))
{
$this->setError($table->getError());
return false;
}
unset($data['id']);
// Bind the data.
if (!$table->bind($data))
{
$this->setError($table->getError());
return false;
}
// Check the data.
if (!$table->check())
{
$this->setError($table->getError());
return false;
}
// Trigger the oonConfigurationBeforeSave event.
$result = $dispatcher->trigger($this->event_before_save, array($this->option . '.' . $this->name, $table, $isNew));
if (in_array(false, $result, true))
{
$this->setError($table->getError());
return false;
}
// Store the data.
if (!$table->store())
{
$this->setError($table->getError());
return false;
}
// Clean the component cache.
$this->cleanCache('_system');
// Trigger the onConfigurationAfterSave event.
$dispatcher->trigger($this->event_after_save, array($this->option . '.' . $this->name, $table, $isNew));
return true;
}
function getComponent()
{
$result = JComponentHelper::getComponent('com_mycomponent');
return $result;
}
}
tables/mycomponent.php
<?php
// No direct access
defined('_JEXEC') or die('Restricted access');
// import Joomla table library
jimport('joomla.database.table');
/**
* Hello Table class
*/
class componentTableMycomponent extends JTable
{
function __construct(&$db)
{
parent::__construct('#__extensions', 'extension_id', $db);
}
public function bind($array, $ignore = '')
{
if (isset($array['params']) && is_array($array['params']))
{
// Convert the params field to a string.
$parameter = new JRegistry;
$parameter->loadArray($array['params']);
$array['params'] = (string)$parameter;
}
return parent::bind($array, $ignore);
}
public function load($pk = null, $reset = true)
{
if (parent::load($pk, $reset))
{
// Convert the params field to a registry.
$params = new JRegistry;
$params->loadJSON($this->params);
$this->params = $params;
return true;
}
else
{
return false;
}
}
public function store($updateNulls = false)
{
// Transform the params field
if (is_array($this->params)) {
$registry = new JRegistry();
$registry->loadArray($this->params);
$this->params = (string)$registry;
}
$date = JFactory::getDate();
$user = JFactory::getUser();
if ($this->id) {
// Existing item
$this->modified = $date->toSql();
$this->modified_by = $user->get('id');
} else {
// New newsfeed. A feed created and created_by field can be set by the user,
// so we don't touch either of these if they are set.
if (!intval($this->created)) {
$this->created = $date->toSql();
}
if (empty($this->created_by)) {
$this->created_by = $user->get('id');
}
}
// Verify that the alias is unique
$table = JTable::getInstance('Yourinstance', 'mycomponentTable');
if ($table->load(array('alias'=>$this->alias, 'catid'=>$this->catid)) && ($table->id != $this->id || $this->id==0)) {
$this->setError(JText::_('COM_CONTACT_ERROR_UNIQUE_ALIAS'));
return false;
}
// Attempt to store the data.
return parent::store($updateNulls);
}
}
Note : your config.xml file should be in models/forms folder.

Categories