Injecting ServiceEntityRepository results in Segfault / nginx Bad gateway 502 - php

We're currently rewriting our codebase, making this change:
// From
public function __construct(EntityManager $em){} // then use $this->em->getRepository(Example::class)
// To:
public function __construct(ExampleRepository $exampleRepo){}
In order to facilitate that, we update the EntityReposity to a ServiceEntityRepository. That helps significantly with unittest and goes well most of the time.
In some rare cases however we get a 502 Bad Gateway and if we run php bin/console
we get a 'Segmentation fault', which (at least to our understanding) means that C just breaks.
During our research we've created the theory that the ServiceEntityRepository load the EntityManager, the EM the Repos, which in turn load the EM again, etc.
Our packages are currently up to date per everyones suggestions everywhere, I'm hoping someone here will come up with a solution, now or maybe in the future. So, does anyone have any idea?
This issue appears related: https://github.com/symfony/symfony/issues/30091

For now I have a "temporary" solution which I'll post here so that others might have at least a work-around if they're searching for a solution. If I find out myself, I'll also update this question.
The error appears to be as is explained in the topic. The solution is to go that step back. Remove the Repository injection from constructor and use the $this->em->getRepository(Example::class) in the methods. The following will not work, as you're still loading the repo in the construct, resulting in the loop:
function __construct(EntityManager $em){
// THIS WILL NOT WORK!
$this->exampleRepo = $this->em->getRepository(Example::class);
}
The issue appears a timing problem. The EntityManager loads the repositories, and each repository loads the Entitymanager, which in turn loads the repositories, ...
This results in an endless loop, which results in the interpreter running out of resources and returning the C error.
Note: Not all repositories have this problem, thusfar we haven't found any pattern yet.

Related

Severely degraded ORM performance in Pimcore X upgrade

We're in the middle of an upgrade to Pimcore 10, and we're experiencing severe performance degradation and a possible memory leak. We're working with PHP v8.1.2, Symfony, and and MySQL v8.
Worth noting - we're talking about VERY little data. The source tables all have fewer than 1000 rows.
I've verified that the generated queries are lightning fast when they run directly from workbench, or when I circumvent the ORM (Doctrine) and run the SQL from its connection object.
When I use the ORM as intended, the load() below should bring back all 219 rows from the table almost instantly. Instead it takes close to a minute.
Nothing changed about this code since before the upgrade, and we never had performance or memory issues before.
I'm new to Pimcore, Symfony, and Doctrine and this is my first time using PHP in probably 10 years. I think the problem is somewhere in the hydration of the model but I'm running low on ideas at this point.
Things I tried:
Running queries in MySQL Workbench (no issues)
Circumventing the ORM to run queries through the application (no issues)
Removed all other service and repository calls so I'm just looking at this situation.
Checked dump() of the hydrated model to see if there are recursion issues (no issues)
// The very simple controller
return $sampleService->getEverything();
// The very simple service
public function getEverything()
{
return $this->sampleRepository->findAll()->load();
}
// The very simple Repository
class SampleRepository
{
protected $listingClass;
public function findAll()
{
return new ($this->listingClass)();
}
}

How to make Date-class to show the same results on 5.6.17 and 5.6.23

First of all I'm aware of this question:
PHP Date bug.
It was finally resolved on PHP 5.6.23. So as I'm moving some of my severs from PHP 5.6.17 to PHP 5.6.23 I want the proper behavior on all of servers. But the project is huge, so to change all the Date-class usages with version check is a bit overhead, as it must be a temporary approach.
So the questions are:
Is there a way to override Date-class on fly on symfony2 project with version check, so it could be the root point, which I could remove then?
Could I somehow log unexpected behavior (some general decision, as
there're a lot of usages as I said).
If it's not possible, you are free to suggest something else.
As I see it you basically have three options. All have their drawbacks and advantages.
Monkey patching the function / method using uopz:
// first backup the original method
uopz_backup (\DateTime::class, 'methodToOverwrite');
// delete the original method
uopz_delete(\DateTime::class, 'methodToOverwrite');
// override the method
uopz_function(\DateTime::class, 'methodToOverwrite', function($arg) {
// do customn stuff like check for versions and handling them differently here
if (version_compare(PHP_VERSION, '5.6.23', '<')) {
// fix stuff
return fixedstuff;
}
return default stuff;
});
// once you are done with your code restore the original method
uopz_restore (\DateTime::class, 'methodToOverwrite');
Pros:
Don't have to change your code besides above
Centralized place for the code
Cons:
High wtfness level because the method does something else then what people expect
You need to parse and properly handle whatever you are expecting in the method
Relies in a non default extension
Always have two paths to test in every instance
Going in an fixing every instance manually:
This would involve having version checks if statements all over your code.
Pros:
It's clear what happens by just looking at the code
Cons:
Having to find all occurrences
Having (possibly) a lot of (the same) version checks if statements littered throughout your code
People need to remember this
Abstract away the issue into a dedicated function / class:
It sounds like this thing that has the issue is something you are doing often. As such it would probably be better to abstract it away by putting it in a function / class.
Pros:
Can easily be unit tested by just testing the function / class
It hides the complexity and the version if statements
Makes code's intent more clearer by having specific methods YourDate::getFirstTuesdayOfWeek()
Cons:
Having to find all occurrences
People need to remember this
Conclusion
Imo the last option is the best because it keeps your code clean, easy to extent and easy to test. And on top of that it has the lowest level of wtfness.

How to test with phpunit this class, which uses connections to the database

I have read in another document that classes which have methods with connections to a database have to be tested by integration tests. I tried to find an example, but I didn't find any, only theory. I've very little experience with testing. Can you give me an example? a link?, something (instead of only theory, because I read a lot), with something like this?. I think this is not an strange case. If its possible with php and sql or similar.
If you dont know about integration tests, how do you test this kinds of problems?
class database{
public $server;
public $database;
public $password;
public $user;
public $descriptor;
function __construct(){
$this->server="localhost";
$this->database="mydb";
$this->user="stackoverflow";
$this->password="1234";
$this->descriptor=mysql_connect($this->server,$this->user,$this->password);
mysql_select_db($this->database,$this->descriptor);
}
function make_request($query){
$response=mysql_query($query,$this->descriptor);
return $response;
}
function close_connection(){
mysql_close($this->descriptor);
}
function number_rows($result_query){
return mysql_num_rows($result_query);
}
}
Look into PHPUnit for unit testing. You can then use mock objects to simulate the dependencies (DB calls) to return dummy data. Because you're trying to test some unit of logic and not that your database layer, it should be acceptable and give you a reasonable amount of confidence that your code is working.
Another option is to use integration tests, but this requires that you put a lot of effort into the setup and teardown of your tests. You need to make sure any data required for your tests exists within your database. It's common to use transactions for these types of tests which you can then rollback after your finished running those tests.
Which code is it you're trying to test? Is it the code that uses your database class? If so, you don't need to introduce PDO, as your database class already provides an abstraction (well, it would be much safer if public $descriptor was private). So, you should start by mocking your database class and then testing the code that uses it. PHPUnit has a sophisticated mocking system.
Another thing you might want to be testing is this database class itself? In that case you'll have to accept the MySQL database dependency, and the speed hit that gives you. Set up a completely dedicated MySQL database for that testing. If you don't mind the speed hit, consider creating the database in a setUp() function and removing it after each test in a tearDown() function.
The third thing you might want to be testing is that your website (or whatever) works as a whole, and connects to the database, etc. This is functional testing (also called integration testing). If your system offers a web services API, then you could use that to test it. Otherwise you could use Selenium (still using PHPUnit) to test by remote control of a real browser. If your tests will only read from the database, you could use your live system; but it would be much more sensible to assume a write will happen at some point, so test against a test version of the website, with its own dedicated test database.
The advantage of functional testing is it high level, testing for all interactions between components, testing the system as the end user will use it. The downside is when a test fails it only tells you something is wrong, not exactly which component is to blame. So we have unit tests to test each component in isolation.
I know you this is more text, less code, than you wanted! But you have actually asked quite a theoretical question! Just try setting up some unit tests of this code, watch what problems occur over the first month of using them, and you'll understand why and where to use mocks.

Updating database on __destruct()?

Do you think it's a good idea?
Let's say you have an application component that is used by other components to retrieve / update data in the db. It's basically a class with get(), set(), update() methods.
Would it be a good idea for that component to update (or set) data only in it's properties when called, and on __destruct to update the db as well? Or should it directly update the db on each set/ update call ?
Updating the database on object destruction smells to me a little bit like a software side effect. That is, an action that takes place in an unexpected and somewhat non-explicit place. It would not be obvious from viewing your code that a database action is happening when __destruct() is called, even if you call it explicitly. Future code maintainers (including yourself) could be easily confused when trying to hunt down a bug involving inconsistent data, but not seeing any calls to the database or method calls resembling data interactions when viewing the code.
I would advise against it.
Attempting to throw an exception from a destructor (called in the time
of script termination) causes a fatal error.
So what about when you have an exception? Any way, I think this is not a good idea, you can't control the work flow, and it is easy to lead a debug hell.

How to begin and rollback a database transaction to wrap a PHPUnit suite for Magento

I'd like to use a transaction rollback method to isolate my database for unit testing purposes. Ideally, I would use a structure something like this:
public static function setUpBeforeClass(){
Mage_Core_Model_Resource_Transaction::beginTransaction();
}
public function testOne(){...}
public function testTwo(){...}
public static function tearDownAfterClass(){
Mage_Core_Model_Resource_Transaction::rollBack();
}
Unfortunately the Mage_Core_Model_Resource_Transaction class doesn't expose public begin/rollbackTransaction functions. I can't find any public Magento functions to meet the requirement. Is there a Zend equivalent that will work?
I guess I could rewrite Mage_Core_Model_Resource_Transaction and add public wrappers for the protected methods, but I'm hesitant to override such a core class.
I have also tried using
$this->model = Mage::getModel('model_being_tested');
$this->model->getResource()->beginTransaction();
...
$this->model->getResource()->rollBack();
and then use the $this->model in the tests but that can't be used in static functions.
Any suggestions or alternative architectures? Thanks in advance.
Frankly speaking, I am going to create some kind of test suite for Magento to make possible writing test cases in your module without taking care of the initialization and so on. Of course I don't have enough time because of the projects, but I want to share the idea wich I am going to use considering database fixtures. I came up with creating a separate database for unit tests (copied from current by test case), because each test case will load initial data for it via fixture. The database connection credentials will be set up prior to Mage::app()->run(), so it will be possible to protect your development copy from possible changes by unit tests.
You cannot rely on transactions, especially in case of saving product... There is set a commit callback for starting re-indexing process and it may cause unpredictable results if you haven't committed data to product tables. As well mysql server may gone away in this case, especially if you have a large database.
UPDATE:
The extension for it:
http://www.ecomdev.org/2011/02/01/phpunit-and-magento-yes-you-can.html

Categories