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.
Related
having problems with this function wipe_data
this wipe_data function my DB cleanup and admin data inserting
but this function shows error:
There is no active transaction
This is my code:
function wipe_data() {
DB::beginTransaction();
$adminData = User::where('role', 'admin')->first();
try {
User::truncate();
User_details::truncate();
User_kyc::truncate();
Token::truncate();`enter code here`
$auto_id = date('Y');
DB::statement("ALTER TABLE ls_users AUTO_INCREMENT = $auto_id");
$admin = new User();
$admin->username = $adminData->username;
$admin->email = $adminData->email;
$admin->password = $adminData->password;
$admin->role = $adminData->role;
$admin->save();
$user_id = User::where('role', 'admin')->value('id');
DB::commit();
} catch (\Exception $ex) {
DB::rollback();
return false;
}
return true;
}
There are some statements that caused implicit commit, including the ALTER TABLE statement you are using.
Therefore, your statement has already been committed before you called DB::commit(), hence an error occurred.
I try this :
public function destroy($id)
{
DB::beginTransaction();
try {
$product = $this->product_repository->find($id);
$result = $product->categories()->detach();
if($result) {
list($status,$instance) = $this->product_repository->delete($id);
}
DB::commit();
return ['status'=>true,'data'=>$status];
} catch (\Exception $e) {
DB::rollback();
return ['status'=>false, 'message'=>$e->getMessage()];
}
}
If the code executed, $this->product_repository->delete($id) not work / not success delete.
But this : $product->categories()->detach();, it works / success deleted.
How to if delete product failed, delete category also failed?
You can't add return statement inside transaction that halts entire process and DB::rollback() is executed.
To switch the return, You can define a boolean variable and make false while you catch exception.
Like this:
public function destroy($id)
{
$success = true;
DB::beginTransaction();
try{
// Your Code
$product = $this->product_repository->find($id);
$result = $product->categories()->detach();
if($result) {
list($status,$instance) = $this->product_repository->delete($id);
}
DB::commit();
}catch(\Exception $e){
DB::rollback();
$success = false;
}
if($success){
// Return data for successful delete
}
else{
// Return data for unsuccessful delete
}
}
Hope you understand.
You can use it like this:
$returnResult = [];
DB::beginTransaction();
try {
...
DB::commit();
$returnResult['status'] = true;
$returnResult['data'] = $status;
} catch (...) {
...
DB::rollback();
$returnResult['status'] = true;
$returnResult['message'] = $e->getMessage();
}
return $returnResult;
I had 2 tables. driver and part_time_available in the same form, when I select driver type = parttime, it'll show part_time_available field(day, start_time, end_time).
How to make condition if user choose fulltime. it didn't store part_time_available field to database.
here's my savehandler code so far :
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) {
\Log::info($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']);
$parttimeAvailability->day = $pta['day'];
$parttimeAvailability->start_time = isset($pta['start_time']) ? $pta['start_time'] : '00:00:00';
$parttimeAvailability->end_time = isset($pta['end_time']) ? $pta['end_time'] : '00:00:00';
$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');
}
}
I mean before running foreach, it needs to check it's parttime or not.
any idea ?
You can give a condition before the whole foreach loop. such as:
if($request->get('driver_type') != 'full_time'){
foreach loop
}
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;
}
}
I have a form which represnts single answer object (this is standard propel generated form I have not changed much there only some validation rules) and another form that represents a collection of answers code as below:
class BbQuestionAnswersForm extends sfForm {
public function __construct($defaults = array(), $options = array(), $CSRFSecret = null) {
parent::__construct($defaults, $options, $CSRFSecret);
}
public function configure() {
if (!$questions = $this->getOption('questions')) {
throw new InvalidArgumentException('The form need array of BbExamQuestion objects.');
}
if (!$taker = $this->getOption('taker')) {
throw new InvalidArgumentException('The form need BbExamtaker object.');
}
if (!$user = $this->getOption('questions')) {
throw new InvalidArgumentException('The form need sfGuardUser object.');
}
foreach($questions as $question) {
$answer = new BbExamAnswer();
$answer->setBbExamQuestion($question);
$answer->setBbExamTaker($taker);
$answer->setCreatedBy($user);
$answer->setUpdatedBy($user);
$form = new BbExamAnswerForm($answer, array('question' => $question));
$this->embedForm($question->getId(), $form);
}
$this->widgetSchema->setNameFormat('solve[%s]');
}
}
Everything(validation, display) goes fine with this form until I try to save it. Part of action which trying to save the form:
...
$this->form = new BbQuestionAnswersForm(null, array('questions' => $this->questions, 'taker' => $this->taker, 'user' => $this->getUser()->getGuardUser()));
if($request->isMethod('post')) {
$this->form->bind($request->getParameter($this->form->getName()));
if($this->form->isValid()) {
if($this->form->save()) {
$this->getUser()->setFlash('success', 'Save goes fine.');
$this->redirect($this->generateUrl('#bb'));
} else {
$this->getUser()->setFlash('error', 'Upps an error occurred.');
}
}
}
When I send valid form I receive "Call to undefined method BbQuestionAnswersForm::save()" error.
I tried to write this method like this:
public function save() {
$conn = Propel::getConnection(ZlecPeer::DATABASE_NAME);
$conn->beginTransaction();
try{
foreach($this->getEmbeddedForms() as $form) {
$form->save();
}
$conn->commit();
} catch(Exception $e) {
$conn->rollback();
echo 'upps something goes wrong';
die($e->getMessage());
return false;
}
return true;
}
but it doesnt work, I receive exception without any message.
What am I doing wrong, how to make save method work?
I believe your BbQuestionAnswersForm is extending the wrong object. It should extend BaseFormDoctrine or possibly BaseBbQuestionAnswersForm if you are using the framework correctly.
Edit: Just noticed you are using propel but it should be the same thing. Try:
class BbQuestionAnswersForm extends BaseBbQuestionAnswersForm
and less likely:
class BbQuestionAnswersForm extends BaseFormPropel
Save method should looks like this:
public function save($con = null) {
if (null === $con) {
$con = Propel::getConnection(BbExamAnswerPeer::DATABASE_NAME);
}
$con->beginTransaction();
try{
foreach($this->embeddedForms as $name => $form) {
if(!isset($this->values[$name]) || !is_array($this->values[$name])) {
continue;
}
if($form instanceof sfFormObject) {
$form->updateObject($this->values[$name]);
$form->getObject()->save($con);
$form->saveEmbeddedForms($con);
} else {
throw new Exception('Embedded form should be an instance of sfFormObject');
}
}
$con->commit();
} catch(Exception $e) {
$con->rollBack();
throw $e;
return false;
}
return true;
}