llaville / php-reflect

Library that adds the ability to reverse-engineer classes, interfaces, functions, constants and more.
http://php5.laurent-laville.org/reflect/
BSD 3-Clause "New" or "Revised" License
60 stars 11 forks source link

How to use the `Log` plugin? #10

Closed stepanselyuk closed 9 years ago

stepanselyuk commented 9 years ago

My phpcompatinfo.json:

{
  "source-providers": [
    {
      "in": ". as current",
      "name": "*.php",
      "exclude": [
        "vendor",
        "tests"
      ]
    },
    {
      "in": "vendor as vendor",
      "name": "/\\.(php|inc|phtml)$/"
    }
  ],
  "plugins": [
    {
      "name": "Analyser",
      "class": "Bartlett\\Reflect\\Plugin\\Analyser\\AnalyserPlugin"
    },
    {
      "name": "Log",
      "class": "Bartlett\\Reflect\\Plugin\\Log\\LogPlugin",
      "options": {
        "logger": {
          "class": "app\\components\\PhpCompatInfoLogger"
        },
        "conf": {
          "reflect.cache": false,
          "reflect.success": true,
          "reflect.complete": true,
          "reflect.progress": {
            "context": true
          }
        }
      }
    },
    {
      "name": "Cache",
      "class": "Bartlett\\Reflect\\Plugin\\Cache\\CachePlugin",
      "options": {
        "adapter": "DoctrineCacheAdapter",
        "backend": {
          "class": "Doctrine\\Common\\Cache\\FilesystemCache",
          "args": [
            "$TMPDIR/bartlett/cache"
          ]
        }
      }
    }
  ],
  "analysers": [
    {
      "name": "Extension",
      "class": "Bartlett\\CompatInfo\\Analyser\\ExtensionAnalyser"
    },
    {
      "name": "Summary",
      "class": "Bartlett\\CompatInfo\\Analyser\\SummaryAnalyser"
    },
    {
      "name": "Condition",
      "class": "Bartlett\\CompatInfo\\Analyser\\CodeCondAnalyser"
    }
  ]
}

and my logger as suggested:

namespace app\components;

use \Monolog\Logger;
use \Monolog\Handler\StreamHandler;

/**
 * Class PhpCompatInfoLogger
 * @package app\components
 */
class PhpCompatInfoLogger extends Logger
{

    public function __construct( $name = 'publigator' )
    {

        $stream = new StreamHandler( \Yii::getAlias( '@runtime/phpcompatinfo.' . $name . '.' . date( 'YmdHis' ) . '.log' ) );
        parent::__construct( $name, [ $stream ] );
    }

}

\Yii::getAlias() give absolute path to file.

But I can't see that file in the path.

I use phpcompatinfo installed via composer, with run-file:

#!/usr/bin/env php
<?php

ini_set( 'memory_limit', -1 );

$vendorDir = __DIR__ . '/vendor';

if (!getenv( "COMPATINFO" )) {

    $home = defined( 'PHP_WINDOWS_VERSION_BUILD' ) ? 'USERPROFILE' : 'HOME';

    $files = array(
        realpath( './phpcompatinfo.json' ),
        getenv( $home ) . '/.config/phpcompatinfo.json',
        '/etc/phpcompatinfo.json',
    );

    foreach ($files as $file) {

        if (file_exists( $file )) {
            putenv( "COMPATINFO=$file" );
            break;
        }
    }
}

require_once $vendorDir . '/autoload.php';

if (PHP_SAPI !== 'cli') {
    return;
}

use Bartlett\CompatInfo\ConsoleApplication as Application;

$application = new Application();
$application->run();

And with run-command:

#!/bin/bash
php ./phpcompatinfo.php -vvv --profile analyser:run . extension
llaville commented 9 years ago

As the LogPlugin works now, since bug fix https://github.com/llaville/php-compat-info/issues/139, I've some questions to ask you

1 - Did you tried with a hard coded value of an absolute name instead of \Yii::getAlias( '@runtime/phpcompatinfo.' . $name . '.' . date( 'YmdHis' ) . '.log' )

2 - Why did you use a custom run-file instead of standard source file bin\phpcompatinfo that is exposed in vendor\bin

3 - Have you check first if your logger is loaded or not. If it's in your include_path, you missed in your custom run-file at least option to handle it with composer autoloader. See https://github.com/llaville/php-compat-info/blob/master/bin/phpcompatinfo#L31

stepanselyuk commented 9 years ago

Hi,

1) Yes, I tried:

public function __construct( $name = 'publigator' )
    {

        $dir = realpath( __DIR__ . '/../../../../runtime/phpcompatinfo' );

        var_dump( $dir );

        $stream = new StreamHandler( $path = $dir . '/' . $name . '.' . date( 'YmdHis' ) . '.log' );

        parent::__construct( $name, [ $stream ] );
    }

2) It's not working when I try to use it via an .sh file, located in my application directory (parent directory of vendor directory), error about not found in require_once $vendorDir . '/autoload.php'.

3) Yes, in my phpcompatinfo.php I've added

require_once __DIR__ . '/components/vendorExt/Bartlett/CompatInfo/ExtensionAnalyser.php';
require_once __DIR__ . '/components/vendorExt/Bartlett/Reflect/PhpCompatInfoLogger.php';

just after

require_once $vendorDir . '/autoload.php';

And I've checked, the class app\components\vendorExt\Bartlett\Reflect\PhpCompatInfoLogger exists, via class_exists (I moved file since last post).

Custom ExtensionAnalyser working file, but not PhpCompatInfoLogger.

llaville commented 9 years ago

Very strange situation.

Here are what I did. Consider /project your application directory. Put a composer.jsonfile at root of your project with following content

{
    "require": {
        "bartlett/php-compatinfo": "~3.6"
    }
}

Install via composer

php composer.phar install

You should get a tree like

project
└───vendor
    ├───bartlett
    │   ├───php-compatinfo
    │   │   ├───bin
    │   │   ├───src
    │   │   │   └───Bartlett
    │   │   │       └───CompatInfo
    │   └───php-reflect
    ├───bin
    ├───composer
    ├───justinrainbow
    │   └───json-schema
    ├───nikic
    │   └───php-parser    
    ├───phpunit
    │   └───php-timer
    ├───sebastian
    │   └───version
    ├───seld
    │   └───jsonlint
    └───symfony
        ├───console
        ├───event-dispatcher
        └───finder

From you application folder project dir, if you run the following command

php vendor\bartlett\php-compatinfo\bin\phpcompatinfo 

Did it run for you ?

stepanselyuk commented 9 years ago

I've installed bartlett/php-compatinfo via composer:

"bartlett/php-compatinfo": "~3.6",
"doctrine/cache": "1.4.*@dev",

I have dirs tree as in the example, except justinrainbow and sebastian.

When I try:

 php ./vendor/bartlett/php-compatinfo/bin/phpcompatinfo

I got the error:

Warning: require_once(/Volumes/WebDev HD/publigator2/application/vendor/bartlett/php-compatinfo/vendor/autoload.php): failed to open stream: No such file or directory in /Volumes/WebDev HD/publigator2/application/vendor/bartlett/php-compatinfo/bin/phpcompatinfo on line 25

Fatal error: require_once(): Failed opening required '/Volumes/WebDev HD/publigator2/application/vendor/bartlett/php-compatinfo/vendor/autoload.php' (include_path='.:/opt/local/share/pear:/opt/local/lib/php/pear') in /Volumes/WebDev HD/publigator2/application/vendor/bartlett/php-compatinfo/bin/phpcompatinfo on line 25
llaville commented 9 years ago

You are not supposed to have a /Volumes/WebDev HD/publigator2/application/vendor/bartlett/php-compatinfo/vendor/autoload.php with a normal composer install.

Instead you should have your composer autoloader at location /Volumes/WebDev HD/publigator2/application/vendor/autoload.php . This is an autoloader for all your vendor dependencies

What version of composer did you used ? run command php composer.phar --version

llaville commented 9 years ago

By adding the vendor tree, I've noticed that I don't installed the require-dev packages list. So, did you have at least Psr\Log and Monolog\Monolog installed (check your vendor folder)

Try to test your logger first outside of phpcompatinfo context to see if it's ok on this side.

<?php

require 'vendor/autoload.php';

use app\components\PhpCompatInfoLogger;

$logger = new PhpCompatInfoLogger();
$logger->addError('is it wrote to file?');
stepanselyuk commented 9 years ago

Instead you should have your composer autoloader at location /Volumes/WebDev HD/publigator2/application/vendor/autoload.php . This is an autoloader for all your vendor dependencies

I have it of course. Original phpcompatinfo not working because $baseDir = dirname(__DIR__); is wrong dir. In my case dirname(__DIR__) is /Volumes/WebDev HD/publigator2/application/vendor/bartlett/php-compatinfo.

So, did you have at least Psr\Log and Monolog\Monolog installed (check your vendor folder)

I've added "monolog/monolog": "1.11.*@dev" before, and now will add "psr/log": "1.0.*@dev" and try to test my logger outside of phpcompatinfo context.

stepanselyuk commented 9 years ago

"monolog/monolog": "1.11.*@dev" has "psr/log": "~1.0" in it's composer.json, so not need to install via my composer.json.

<?php

require 'vendor/autoload.php';

require_once __DIR__ . '/components/vendorExt/Bartlett/Reflect/PhpCompatInfoLogger.php';
use app\components\vendorExt\Bartlett\Reflect\PhpCompatInfoLogger;

$logger = new PhpCompatInfoLogger();
$logger->addError( 'is it wrote to file?' );

It is working (I see message and have log file). The app namespace doesn't exists in autoload.php because it handled by Yii autoloader, not in composer autoloader directly. Therefore I've required the file directly.

llaville commented 9 years ago

Take care then to put the right definition in phpcompatinfo.json

On first time, I see only app\\components\\PhpCompatInfoLogger and later you use other location.

On my side I've tested the LogPlugin without problem

And all run fine !

My last TIP for today, is :

CU tomorrow for I hope the end of story with a a good conclusion

stepanselyuk commented 9 years ago

be sure that there are no conflicts between composer autoloader and yii

Yii2 installed via composer so there is no conflicts.

My current phpcompatinfo.json:

{
  "source-providers": [
    {
      "in": ". as current",
      "name": "*.php",
      "exclude": [
        "vendor",
        "tests"
      ]
    },
    {
      "in": "vendor as vendor",
      "name": "/\\.(php|inc|phtml)$/"
    }
  ],
  "plugins": [
    {
      "name": "Analyser",
      "class": "Bartlett\\Reflect\\Plugin\\Analyser\\AnalyserPlugin"
    },
    {
      "name": "Log",
      "class": "Bartlett\\Reflect\\Plugin\\Log\\LogPlugin",
      "options": {
        "logger": {
          "class": "\\app\\components\\vendorExt\\Bartlett\\Reflect\\PhpCompatInfoLogger"
        },
        "conf": {
          "reflect.error": true,
          "reflect.cache": true,
          "reflect.success": true,
          "reflect.complete": true,
          "reflect.progress": {
            "context": true
          }
        }
      }
    },
    {
      "name": "Cache",
      "class": "Bartlett\\Reflect\\Plugin\\Cache\\CachePlugin",
      "options": {
        "adapter": "DoctrineCacheAdapter",
        "backend": {
          "class": "Doctrine\\Common\\Cache\\FilesystemCache",
          "args": [
            "runtime/phpcompatinfo/cache"
          ]
        }
      }
    }
  ],
  "analysers": [
    {
      "name": "Extension",
      "class": "\\app\\components\\vendorExt\\Bartlett\\CompatInfo\\ExtensionAnalyser"
    },
    {
      "name": "Summary",
      "class": "Bartlett\\CompatInfo\\Analyser\\SummaryAnalyser"
    },
    {
      "name": "Condition",
      "class": "Bartlett\\CompatInfo\\Analyser\\CodeCondAnalyser"
    }
  ]
}
stepanselyuk commented 9 years ago

Scanning for my vendor directory has been finished!

Data Source Analysed

Directories                                        841
Files                                             4727

Cache: 0 hits, 4727 misses
Time: 4.81 hours, Memory: 515.25Mb

I don't know why it was not used cache, because the cache have the data from previous scans.

llaville commented 9 years ago

The cache is only reused on the second run and later (unless you clear its contents).

Be carefull when you use LogPlugin with these parameters. It will generate a lot of data in your log file, and of course consume memory and time too, especially with lot of file in a data source to parse.

llaville commented 9 years ago

I consider the help/support over. If it's not true, reopen this issue !

stepanselyuk commented 9 years ago

Log plugin still not worked for me.

Be carefull when you use LogPlugin with these parameters. It will generate a lot of data in your log file, and of course consume memory and time too, especially with lot of file in a data source to parse.

I use this settings for testing, in case to see anything. But nope, I don't see the log file.

stepanselyuk commented 9 years ago

In \Bartlett\Reflect\Builder::parseMethodCall I've made changes:

if ($var instanceof \PhpParser\Node\Expr\PropertyFetch) {

            if ($var->name instanceof \PhpParser\Node\Expr\Variable) {
                $varName = '$' . $var->name->name;
            } else {

                if ($var->name instanceof \PhpParser\Node\Scalar\String
                    || $var->name instanceof \PhpParser\Node\Expr\ArrayDimFetch
                ) {
                    // can't do it
                    return;
                } else {
                    $varName = (string) $var->name;
                }

            }
//...

I think you need to check availability of (string) $var->name; before run this operation. Or try to catch fatal error.