Customizing Monolog HTML formatter for email

Monolog can send emails when there’s an error, but in the provided HTML formatter I missed the REQUEST_URI and REMOTE_ADDR that triggered the error.

Some info is in the exceptions section, but not always and needs horizontal scrolling in the email client ๐Ÿ™‚

So I just replicated the HtmlFormatterย and added some lines (dirty hacks).

Added service class

ย <service id="app.monolog.formatter.html" class="App\Service\MonologEmailFormatter" public="false" />

Change formatter service ID

# app/config/config_prod.yml
swift:
    type: swift_mailer
    from_email: "php@example.com"
    to_email: ["info@example.com"]
    subject: 'Error'
    level: error
    formatter: custom.monolog.formatter.html
    content_type: text/html

UPDATE: You might be interested in https://stefanoalletti.wordpress.com/2017/03/09/symfony-and-monolog-how-use-processor-in-your-project/

Advertisements

Using Symfony Entity via Doctrine in custom project

With my colleague we had to code a custom code for a legacy/custom codebase that would use Symfony2 entities via Doctrine for a couple of months.

composer.json included the following:

{
    "minimum-stability": "stable",
    "require": {
        "php": ">=5.3.9",
        "doctrine/orm": "2.4.*",
        "symfony/symfony": "2.7.*",
        "symfony/dependency-injection": "2.7.*",
        "symfony/validator": "2.7.*",
        "symfony/doctrine-bridge": "2.7.*"
    },
    "autoload": {
        "psr-0": {
            "": "src/"
        }
    }
}

We we’re getting the following PHP error:

Warning: require(/var/tmp/__CG__CoreBundleEntityProduct.php): failed to open stream: No such file or directory in /Volumes/data/Sites/legacy-proj/trunk/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php on line 209

Fatal error: require(): Failed opening required '/var/tmp/__CG__CoreBundleEntityProduct.php' (include_path='.:') in /Volumes/data/Sites/legacy-proj/trunk/vendor/doctrine/common/lib/Doctrine/Common/Proxy/AbstractProxyFactory.php on line 209

The solution was to regenerate the proxy classes. The finale code looked like this:

<?php
// src/Wrapper/bootstrap.php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;

$loader = require_once __DIR__.'/autoload.php';

$paths = array(dirname(__FILE__).'/../../src/SF_PROJECT/CoreBundle/Entity');
$isDevMode = false;

$dbParams = array(
    'driver'   => 'pdo_mysql',
    'user'     => 'root',
    'password' => '',
    'dbname'   => 'centralis',
);

$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);
$config->setAutoGenerateProxyClasses(true);
$entityManager = EntityManager::create($dbParams, $config);

$domain = $entityManager->getRepository('SF_PROJECT\CoreBundle\Entity\Domain')->find(1);
if ($domain === false) {
    return;
}
<?php
// src/Wrapper/autoload.php
use Doctrine\Common\Annotations\AnnotationRegistry;
use Composer\Autoload\ClassLoader;

/**
 * @var ClassLoader $loader
 */
$loader = require __DIR__.'/../../vendor/autoload.php';

AnnotationRegistry::registerLoader(array($loader, 'loadClass'));

return $loader;

After that the code generated the following classes in /var/tmp

mike@mike ~ $ ls /var/tmp/__CG*
/var/tmp/__CG__AtechNetCoreBundleEntityAlbum.php
/var/tmp/__CG__AtechNetCoreBundleEntityAttribute.php
/var/tmp/__CG__AtechNetCoreBundleEntityAttributeOption.php
/var/tmp/__CG__AtechNetCoreBundleEntityCustomer.php
/var/tmp/__CG__AtechNetCoreBundleEntityDomain.php
/var/tmp/__CG__AtechNetCoreBundleEntityLanguage.php
/var/tmp/__CG__AtechNetCoreBundleEntityStore.php
/var/tmp/__CG__AtechNetCoreBundleEntityStoreMovement.php
/var/tmp/__CG__AtechNetCoreBundleEntityUser.php
/var/tmp/__CG__AtechNetCoreBundleEntityVendor.php

Symfony Components in Legacy Code

I just watched PHPNW13 Saturday Track 3 Talk 4: Hugo Hamon – Bringing the Symfony Components into your Legacy Code. The talk was great with the example slides.
Also the mentioned tools phploc (PHP Lines Of Code perhaps ๐Ÿ™‚ and phpcpd (PHP Copy/Paste Detector) are great.

UPDATE 2015-04-05: Jakub Zalas posted his research data about Symfony adoption

PHPloc example output:

phploc 2.1.0 by Sebastian Bergmann.

Directories 280
Files 1426

Size
 Lines of Code (LOC) 263934
 Comment Lines of Code (CLOC) 46562 (17.64%)
 Non-Comment Lines of Code (NCLOC) 217372 (82.36%)
 Logical Lines of Code (LLOC) 90186 (34.17%)
 Classes 66072 (73.26%)
 Average Class Length 39
 Minimum Class Length 0
 Maximum Class Length 17069
 Average Method Length 4
 Minimum Method Length 0
 Maximum Method Length 1999
 Functions 4640 (5.14%)
 Average Function Length 6
 Not in classes or functions 19474 (21.59%)

Cyclomatic Complexity
 Average Complexity per LLOC 0.35
 Average Complexity per Class 14.18
 Minimum Class Complexity 1.00
 Maximum Class Complexity 10218.00
 Average Complexity per Method 2.58
 Minimum Method Complexity 1.00
 Maximum Method Complexity 1542.00

Dependencies
 Global Accesses 9177
 Global Constants 5986 (65.23%)
 Global Variables 720 (7.85%)
 Super-Global Variables 2471 (26.93%)
 Attribute Accesses 34977
 Non-Static 34535 (98.74%)
 Static 442 (1.26%)
 Method Calls 17084
 Non-Static 16260 (95.18%)
 Static 824 (4.82%)

Structure
 Namespaces 1
 Interfaces 0
 Traits 0
 Classes 1667
 Abstract Classes 9 (0.54%)
 Concrete Classes 1658 (99.46%)
 Methods 13905
 Scope
 Non-Static Methods 13662 (98.25%)
 Static Methods 243 (1.75%)
 Visibility
 Public Methods 13589 (97.73%)
 Non-Public Methods 316 (2.27%)
 Functions 728
 Named Functions 727 (99.86%)
 Anonymous Functions 1 (0.14%)
 Constants 861
 Global Constants 487 (56.56%)
 Class Constants 374 (43.44%)