Use TIMESTAMPDIFF to identify long running cronjobs in Magento2

magento2_teaser_patch

Improving performance in cron jobs can be very time consuming. Even just figuring out where to start can take hours.

I came up with an idea that really helped me to locate potential performance killer just by checking the execution time by using TIMESTAMPDIFF. For example:

Output example:

The runtime can be a sign of high memory or CPU usage, therefore, you should probably look at those cron jobs first.

Magento 2 – How to fix ” The order confirmation email is not sent “

Magento2 Teaser

This morning I was working on an email issue ( multi-store ) where customers were able to purchase but didn’t receive the order confirmation email.

As always, I had a look at what has been deployed recently and checked pretty much all logs on the production environment. Unfortunately, I couldn’t find anything.

I started looking at database changes, especially the core_config_data table, and noticed that the template for the order confirmation was defined twice. This was kind of weird because those email settings were set to ” Use System Value “.

I ended up deleting the IDs 4293, 4296, 4299 which has fixed the issue immediately. I still don’t know why those values were set twice, but I hope this will help someone…sometime.

Magento 2.4.x, Elastic Search 7.9.1 on Alpine Linux 3.12, jdk/bin/java: No such file or directory

Magento2 Teaser

While setting up a new local test environment specifically for Magento 2.4.x with Elastic Search on Alpine Linux ( Docker ) I had some problems with getting elastic search up and running.

The first issue I had was related to a missing home path of JAVA. Because of that, I wasn’t able to start Elastic Search at all.

I’ve fixed it by setting the missing path for JAVA_HOME which I have added later to my profile settings. https://stackoverflow.com/questions/35325856/where-to-set-system-default-environment-variables-in-alpine-linux

The second issue was related to the JAVA version inside the docker container.

Alpine Linux has the required version in the repository, which made it easy to install the missing package with apk.

Magento 2.3.x – Unit Tests with ScopeConfigInterface

Magento2 Teaser

Imagine you have a helper class that is responsible for downloading and processing JSON files. This is something you don’t want to test manually all the time. I didn’t implement many unit tests in the past, simply because it wasn’t necessary or just not scoped in a project. However, there are cases where you actually save a lot of valuable time with just a few simple unit tests.

In this article I would like to show you how to inject store configurations ( ScopeConfigInterface ) to your mocked classes which are necessary to test multiple scenarios. In the following example I am going to test a helper class and make sure the following scenarios are working as expected.

  1. Is the module enabled in Stores > Configuration > General?
  2. Is a URL defined?
  3. Does the URL return a correct HTTP response?
  4. Is the downloaded content a valid JSON string?

Here is how my module looks like. I basically created a new helper Helper\Curl.php and a unit test file Test\Unit\Helper\CurlTest.php.

I’ve added some basic methods to the helper, such as isEnabled(), getFileUrl(), getStatusCode(), isJson() and downloadFile(). Nothing fancy, just a helper that can download a file.

Usually if you want to use system variables from core_config_data you have to inject the ScopeConfigInterface in your constructor. In unit tests it is quite similar. First, you have to create a mockup of the ScopeConfigInterface.

Next, you need a mockup of the Context, but this is not always the case.

Now you can inject these two mockups to the helper by using setConstructorArgs like in the below example.

Now you can define values for the scope configuration. This allows you to enable or disable your module or set random values and see how your code behaves. In the below example, I simply enable the module ( $isEnabled ) and set the file url ( $fileUrl ) to https://raw.githubusercontent.com/ljharb/json-file-plus/master/package.json which I will test with assertEquals and assertNotContains.

I also define an expected value for the CURL httpStatus and an expected return value of isJson(). Okay, lets run the test and see what happens.

All assertions within the test have succeeded. Let’s see what happens when I change the URL slightly. It should return a 404.

Yes, the test fails because I’ve received a status code 404 instead of 200.

That’s it. If you have questions or need help, please let me know in the comments.

October CMS – Widget OC Media Manager

October CMS Logo

If you work with the form elements fileupload or mediafinder in combination with user admin roles ( Settings > Administrators ) you may end up with the following error while saving a model.

In order to fix that, you must review the permissions of your admin user account for Upload and manage media contents – images, videos, sounds, documents. and select Allow or Inherit, depending on how you setup your roles.

October CMS - Admin User Roles Media

After saving the permissions, you should be able to upload or select an image and save the model.

October CMS – How To Fix Broken Thumbnails

October CMS Logo

I recently started setting up a dockerized October CMS environment based on Alpine Linux, MariaDB and PHP-FPM which was actually a very straightforward process. However, for some reason the integrated image resizer didn’t create thumbnails of uploaded images.

October CMS - Broken Thumbnail Image

Unfortunately there was nothing in the log files which could help me to identify the cause of the problem. After checking the file permissions, I decided to trace back the issue and found the reason in file vendor/october/rain/src/Database/Attach/Resizer.php.

The method getMimeType() returned always null, which broke the entire image manipulation process.

After a quick research I found out that getMimeType requires php_fileinfo which I simply forgot to set in my Dockerfile. After adding php7-fileinfo and rebuilding the container, the issue was finally fixed.

 

PHP message: PHP Fatal error: Interface ‘SessionHandlerInterface’ not found in /var/www/src/vendor/ laravel/framework/src/Illuminate/Session/FileSessionHandler.php on line 10

Today I successfully installed my first October CMS project locally via composer / command line. The installation was pretty straightforward and worked surprisingly well on my Alpine Linux docker container which includes NGINXPHP-FPM and MariaDB.

However, when I tried to open the front-end I got the following error.

After a quick research I found the solution on Stackoverflow. I basically forgot to install the PHP extension php7-session inside my docker container. I manually installed the missing extension, but also updated my Dockerfile in case I have to rebuild my container.

After that I manually killed all PHP processes to make sure php-fpm loads the new extension with the next page reload.

 

Working with files and folders in Magento2

Working with files and folders in Magento2

Magento® 2 offers you a bunch methods for file and folder operations, which allow you to implement quality modules in a short time. Especially if you are planning to publish modules on the Magento Marketplace you have to use those functions, otherwise you won’t meet Magento’s coding standards. In order to have access to cool functions like mkdirRecursive, deleteDirectory or changePermissionsRecursively simply inject \Magento\Framework\Filesystem\Driver\File in your constructor.

Once you have re-compiled your code, you should be able to use those functions in your modules like below.

More functions are listed below.

1. Check if the file or folder exists on the file system.

2. Returns information like ctime and mtime or sizeatimeuid and gid.

3. Check if a file is readable

4. Check if path is a file ( not folder )

5. Check if path is a directory ( not a file )

6. Get content of a regular file

7. Check if a regular file is writable ( not a folder )

8. Return the parent directory of a path

9. Create a new directory with specific permissions

10. Create a new directory recursively

11. Reads a directory and returns an array with all paths of its sub-directories

12. Search for a path

13. Rename a regular file or a directory

14. Copy a file from A to B

15. Create a symlink

16. Delete a regular file ( not a file )

17. Delete a directory recursively

18. Change permissions of a directory

19. Change permissions of a directory and file recursively

20. Manipulate the access and modification time of a file

21. Write content to a file

22. Opens a file like fopen

23. Returns a line from the given handle

24. Reads a file like fread.

25. Reads a CSV file like fgetcsv

26. Returns position of a pointer like ftell

27. Seeks to a specific offset like fseek

28. Returns true if pointer is at the end of a file

29. Close a file

30. Write to a file like fwrite

31. Write one row to a CSV file

32. Flush output of a file. See fflush.

33. Lock a file before write content to a file

34. Unlock a file after all file manipulations are done

35. Return a absolute path

36. Fixes a path separator

37. Reads a directory recursively and returns paths as an array

38. Return the real path like realpath

39. Returns a path for link

Cheers

UI Components and searchResultToOutput in Magento2

Today I had to fix the following issue in a custom module. The error appeared on the UI Component list view.

I found the reason of the problem in the di.xml file. All what was missing was the following virtualType node. After adding this and re-compiling the code, the list view was fixed.

Update composer.lock without updating code

Recently I had to fix a broken composer.lock but without actually updating code. I have found the composer option ” nothing ” which updates the composer.lock file only.

Once the command ran successfully, you should see a line ” Writing lock file ” in the output.

If you have issues with dependencies you can update the composer.lock file with –ignore-platform-reqs.