brazorf
brazorf

Reputation: 1961

Laravel4, access instance methods within a Facade implementation ends up in PHP fatal: call to undefined method

This is a test i am running to understand how framework works. I've coded a trivial facade implementation, a service provider and i properly registered it. Code:

// This is the facade 
<?php
namespace my\facades;
use Illuminate\Support\Facades\Facade;

class DateHelper extends Facade {
    /**
     *  Get the registered name of the component.
     *  @return string
     */
    protected static function getFacadeAccessor() { 
        // Return the instance key name in the IoC Container.
        return 'my.utils.dateHelper'; 
    }

}

// This is the service provider
<?php
namespace my\providers;
class MyServiceProvider extends \Illuminate\Support\ServiceProvider {
    /**
     *  Register the service provider.
     */
    public function register() {

    // Register the date handler
    $this->app['my.utils.dateHelper'] = $this->app->share(function($app) {
            return new \my\utils\DateHelper();
    });



        // Shortcut so developers don't need to add an Alias in app/config/app.php
        $this->app->booting(function(){
            $loader = \Illuminate\Foundation\AliasLoader::getInstance();

            $loader->alias('DateHelper', '\my\utils\DateHelper');

        });
    }
}
// This is the actual implementation
class DateHelper {
    public static $UI_DATE_FORMAT = 'd/m/y';
    public static $UI_DATETIME_FORMAT = 'd/m/y H:i:s';

    /**
     * 
     *  Enter description here ...
     *  @param DateTime $date0
     *  @param DateTime $date1
     */
    public function compare(mixed $date0, mixed $date1) {
        if (is_string($date0)) {
            $date0 = $this->a($date0)->getTimestamp();
        }
        if (is_string($date1)) {
            $date1 = $this->a($date1)->getTimestamp();
        }
        return $date0 < $date1 ? -1 : $date1 > $date0 ? 1 : 0;
    }

    /**
     * 
     *  Enter description here ...
     *  @param string $inputDate
     */
    public function a( $inputDate) {
        return \DateTime::createFromFormat(self::$UI_DATE_FORMAT, $inputDate);
    }
}

Now, i.e. from a Controller, i am able to

Methods are properly resolved. What is not working is the line of the sort

$date0 = $this->a($date0)->getTimestamp();

where i get a PHP fatal stating that

PHP Fatal error:  Call to undefined method DateHelperTest::a()

I think this has something to do with magic methods. I tried to invoke them statically, but nothing changes. How i can i invoke

a()

from the

compare()

body?

== EDIT ==

I am writing a test against this facade, the like of this

<?php
class DateHelperTest extends \TestCase {

    public function testComparison() {
        // Compare strings
        $d0 = "01/01/2012";
        $d1 = "02/01/2012";
        $this->assertEquals(DateHelper::compare($d0, $d1), 1);
        $this->assertEquals(DateHelper::compare($d1, $d0), -1);
        $this->assertEquals(DateHelper::compare($d0, $d0), 0);

        // Compare DateTimes
        $dateTime0 = new DateTime($d0);
        $dateTime1 = new DateTime($d1);
        $this->assertEquals(DateHelper::compare($dateTime0, $dateTime1), 1);
        $this->assertEquals(DateHelper::compare($dateTime1, $$dateTime0), -1);
        $this->assertEquals(DateHelper::compare($dateTime0, $dateTime1), 0);
  }

  public function testParser() {
    $sample = "01/02/2012";
    $d = DateHelper::parseInput($sample);
    $this->assertEquals($d->format("d/m/Y"), $sample);
    $this->assertEquals($d->format("d"), "01");
    $this->assertEquals($d->format("m"), "02");
    $this->assertEquals($d->format("Y"), "2012");
  }

}

I just spotted a weird thing i didn't see at first. Error states that

PHP Fatal error: Call to undefined method DateHelperTest::parseInput() in /var/www/my/app/my/utils/DateHelper.php on line 15

so, what's this? the $this->fooBar method in DateHelper is resolved to DateHelperTest->foobar()?

Upvotes: 0

Views: 699

Answers (1)

J.T. Grimes
J.T. Grimes

Reputation: 4272

I haven't seen the AliasLoader used in that way before, but I think your problem might be there. The alias should point to the Facade, not to the actual class.

(I'd also encourage you to rename your facade to make it clearer which class is the facade and which is the underlying class -- I'd bet you're going to burn yourself at least once by using the wrong namespace and getting a class you don't expect.)

Upvotes: 2

Related Questions