I'm writing a converter that takes a document from database (mongo db), does some magic with its fields and writes it back. Repeat for all relevant docs.
The problem is, after successful processing EntityManager#flush() just silently crashes not committing any changes to db or returning an error code.
I encountered this crash before but I've been able to evade it by reducing quantity of entities to flush(). Now it won't work even with one.
The code goes like this:
public function convertTagsAction() {
$result = [];
$result['docs processed'] = 0;
$result['tags added'] = 0;
$repo = $this->getRepo('Portal');
$cnt = 0;
$dm = $this->getDM();
$docs = $repo->findBy([...]);
$result['docs to process'] = count($docs);
foreach($docs as $doc) {
....//executing just for ONE doc at the moment
$result['docs processed']++;
//file_put_contents('1.txt', print_r($doc, true));
//Everything is ok in the file
$dm->persist($doc);
echo $dm->getUnitOfWork()->size();
// returns 6087 which I deem strange
//this helped me before to manage this problem
$cnt++;
if ($cnt >= 20) {
$dm->flush();
$cnt = 0;
}
}
try {
$dm->flush();
} catch (Exception $e) {
echo $e->getMessage(); //Nah, won't tell me anything
}
return $this->success($result);
}
So now, whenever flush() is called, the script just quits and not even returns any output (should do so in the last line). Any ideas how to solve it?
Related
I'm working on an asynchronous process on a PHP project. I'm using a library named spatie/async. The code snippet is like below :
foreach (range(1, 2) as $i) {
$pool->add(function () use ($i) {
// Do a thing
try {
$result = $i / 0; // This will cause an error
return "Works";
} catch (\Exception $e) {
return -1;
}
})->then(function ($output) {
// Handle success
echo (output . "\n");
})->catch(function ($exception) {
// When an exception is thrown, it's caught and passed here.
echo "Sounds good, but don't work\n";
})
}
$pool->wait();
All I want is when the $result got an error, it will go into the inner catch, but instead, it goes down to the bottom catch which causing a different result from what I want.
The result that I want is :
-1
-1
But instead, the result is :
Sounds good, but don't work
Sounds good, but don't work
Can anyone help me to achieve the result as I want?
The problem of your code is, that it does not throw an Exception in the add method call. A division by 0 is just causing an error, but not ein exception. Instead of changing the whole php error handler, I 'd suggest to extend your logic a little bit in your add method call.
$divisor = 0;
$pool->add(function() use ($i, $divisor) {
try {
if ($divisor === 0) {
throw new \LogicException('Division by zero!');
}
return $i / $divisor;
} catch (\LogicException $e) {
return -1;
}
});
Another solution could be changing the error handling for the pool method call.
set_error_handler(function () {
throw new \LogicException('Ouch!');
});
$pool->add(function() use ($i) {
try {
$result = $i / 0;
} catch (\LogicException $e) {
return -1;
}
});
restore_error_handler();
Caution! Changing the error handler affects all upcoming errors. Even the errors thrown in your used library. Keep in mind, that these are code snippets. This is not tested or thougt to be used in production. Hope that helps out a little bit.
I have a Laravel Job that is being dispatched. The job gets some records to process then calls an API with each. The API could occasionally could throw an error e.g. HTTP500 etc. This library (Goose) uses Guzzle.
I want to catch the error, flag the record to try again later and continue with the rest of the records in the loop.
My code is as follows but when an error occurs, the foreach loop ceases and the job does not continue.
My guess is that the Job Handler in Laravel is throwing a fatal error and the job is being halted at a higher level.
public function extractArticles() {
$articles = $this->fetchArticlesToExtract();
$goose = new GooseClient();
foreach($articles as $article) {
try {
//Get the Article Data - Errors can happen here
$articleData = $goose->extractContent($article->source_url);
//Do Some Processing
$article->save();
}
catch (\Goose\Exception $e) {
//Set a flag to come back later
//Try continue with next record
continue;
}
}
return;
}
How can I tell the Job to continue? There is only a small set of errors that can occur here and I have written the logic to 'try again', so I'm happy to not stop the job completely.
You have too many } and they are in the wrong places
public function extractArticles() {
$articles = $this->fetchArticlesToExtract();
$goose = new GooseClient();
foreach($articles as $article) {
try {
//Get the Article Data - Errors can happen here
$articleData = $goose->extractContent($article->source_url);
//Do Some Processing
$article->save();
}
//} removed
catch (\Goose\Exception $e) {
//Set a flag to come back later
//Try continue with next record
continue;
}
}
return;
}
I am trying to import data with Symfony 3.4. And I have successfully finished the task. In the end, I run into some problems, and I don't know how to solve it. So, what am I doing:
taking data from an Excel file and store it in the database.
on refresh, I delete the table and again go through the excel file and store values in the database
I just saw that primary keys are getting updated. It is not a problem, but it bothers me. So if I add 130 rows, delete them, store them again, the primary key will start from 260, and back from 390 and so on.
So I decided not to delete a table, but to truncate it. And the first time it creates 130 rows. On refresh, it truncates the table but stores only five rows instead of 130, and I cannot find the bug. So on delete everything works fine, but on truncate, the second time it stores only five rows instead of 130. Here is my code, and if someone sees the bug, please let me know:
public function importMappedAttributes($mappedAttributesValues)
{
if (!$this->checkIfTableIsEmpty()) {
$this->truncateTable();
}
try{
foreach ($mappedAttributesValues as $value) {
$mappedAttributes = new MappedAttribute();
$mappedAttributes->setAkeneoAttribute($value['result_one']);
$mappedAttributes->setXmlAttribute($value['result_two']);
$mappedAttributes->setXmlPath($value['result_three']);
$mappedAttributes->setMetadata($value['result_four']);
$this->getEntityManager()->persist($mappedAttributes);
$this->getEntityManager()->flush();
}
} catch (\Exception $e){
throw new \Exception('Something went wrong!');
}
}
The first part checks if the table is empty and if is not truncate it:
private function checkIfTableIsEmpty() {
$numberOfRows = count($this->getEntityManager()->getRepository('ImportAttributesBundle:MappedAttribute')->findAll());
if ($numberOfRows > 1) {
return false;
}
return true;
}
public function truncateTable() {
$em = $this->getEntityManager();
$classMetaData = $em->getClassMetadata('ImportAttributesBundle:MappedAttribute');
$connection = $em->getConnection();
$dbPlatform = $connection->getDatabasePlatform();
try {
$connection->query('SET FOREIGN_KEY_CHECKS=0');
$q = $dbPlatform->getTruncateTableSql($classMetaData->getTableName());
$connection->executeUpdate($q);
$connection->query('SET FOREIGN_KEY_CHECKS=1');
$connection->commit();
}
catch (\Exception $e) {
$connection->rollback();
}
}
The problem was that $this->getEntityManager()->flush(); should go outside the foreach. That was causing unexpected behavior and when I put it after the foreach everything worked fine.
I've use Larvel 5.0 with Database transaction all the method in my previous web application it work as well and we are really love it because this application help me much more than our estimated
so we have create another webs application by using this newest version of this framework and used the same Database structure but finaly it would not work for me and another one to.
I have as more peoples and post on some toturial website for asking any belp but not yet get any solution so I record this video for sure about this case.
Issue: My issue I've disabled (//commit()) method all data still can insert into Database.
final function Add()
{
if ($this->request->isMethod('post')) {
//No you will see this method use with Try Catch and testing again
//DB::beginTransaction(); // Ihave testing with outside of try and inside again
Try{
DB::beginTransaction();
$cats = new Cat();
$catD = new CategoryDescriptions();
$cats->parent_id = $this->request->input('category_id');
$cats->status = ($this->request->input('status')) ? $this->request->input('status') : 0;
if (($res['result'] = $cats->save())== true) {
$catD->category_id = $cats->id;
$catD->language_id = 1;
$catD->name = $this->request->input('en_name');
if (($res['result'] = $catD->save()) === true) {
$catD2 = new CategoryDescriptions();
$catD2->category_id = $cats->id;
$catD2->language_id = 2;
$catD2->name = $this->request->input('kh_name');
$res['result'] = $catD2->save();
}
}
if(!empty($res)) {
//DB::commit();
}
return [$res,($res['result'] = $catD->save())];
}catch(\Exception $e){ // I have already try to use Exception $e without backslash
DB::rollback();
}
}
$cat = Cat::with(['CategoryDescriptions', 'children'])->where('status', 1)->get();
return view('admin.categories.add', ['cat' => $cat]);
}
You can check on my video to see that .
Check on my video
I don't know why your code did not work. But you can try with this code I think it's will work. Laravel transaction documentation
try{
DB::transaction(function)use(/*your variables*/){
// your code
});
}catch(\PDOException $exception){
//debug
}
If any exception occurs it will automatically rollback. If you want manual rollback then inside transaction you can throw a manual exception based on your logic.
I have a php script to pipe through a mail,
class mailTest
{
// (some code here)
private function saveToDb()
{
// (some code here)
$select = $this->pdo->query("SELECT * FROM tbl_reques WHERE terminal_id = $term AND request_status ='' ");
$select = $select->fetchAll();
if (count($select) > 0) {
echo "Call already Exist (DISCARD)";
} else {
$select_tech = $this->pdo->query("SELECT * FROM tbl_email WHERE terminal_id = $term");
$select_tech = $select_tech->fetchAll();
// (some code here)
}
}
private function sendEmail()
{
$this->today = time();
$this->maildate = date("Y-m-d H:i:s", strtotime('-5 minutes', $this->today));
$select = $this->pdo->query("Select * from tbl_reques WHERE maildate >= '$this->maildate' ");
// some code here
mail($this->from_email, $this->subject, $newmsg, $headers);
}
}
The problem is any time the condition is False i.e echo "Call already Exist (DISCARD)"; The code will not go to the Next Function. i.e the program get halt.
PLS is there a way that if that condition is not met, the program will JUMP to next function for continuation of execution. Or is it possible to use GOTO statement.
Pls what is the best way to handle this in PHP.
Thanks
You have a couple option for this. You can return at the point of failure. Which would exit the function at this point and then do whatever is next in the script being ran. Be sure to do the clean up before your return.
if(count($select) > 0) {
echo "Call already Exist (DISCARD)";
//Clean up if needed
return; //You could also return the message
//or an error code and have another
//evaluation based on that.
} else {
// Or passes
}
You could call the next function but this would be a very bad flow in my opinion
if(count($select) > 0) {
echo "Call already Exist (DISCARD)";
//Clean up if needed
$this->sendEmail();
} else {
// Or passes
}
The reason this would be bad is if say in the script you have
$mailTest = new mailTest();
$mailTest->saveToDb();
$mailTest->sendEmail(); //When the above fails this is called twice.
You could likewise throw an exception
if(count($select) > 0) {
echo "Call already Exist (DISCARD)";
throw new Exception("Call already Exist (DISCARD)");
} else {
// Or passes
}
Now you need to use try and catch
$mailTest = new mailTest();
try {
$mailTest->saveToDb();
catch (Exception $e){
//Do something with $e
//Clean up the failure if needed
}
$mailTest->sendEmail();
There is a finally block as well which would run in cases where your catch stops the script.
PHP in fact has a GOTO statement, see http://php.net/manual/de/control-structures.goto.php
However, it is considered bad style to use it, or in the words of #Konamiman
Unless you are programming in assembler, GOTO should always be treated the same way as the life vest of the airplanes: it is good to have them available, but if you need to use them it means that you are in big trouble.
You can call a function simply by writing its name followed by brackets. In the case of class functions you apply it to $this:
$this->sendEmail();