Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel extend a vendor class installed from composer

Hi I am using the following package https://github.com/jayhealey/Robots to add a different robots.txt file per environment I have on my application. However this is missing one method I am using on my application which is the crawl delay i.e.

Crawl-delay: 3600

Now i have the following folder from the composer install of this package:

vendor/healey/robots/src/Healey/Robots/Robots.php and this starts as so:

<?php namespace Healey\Robots;

class Robots
{....}

Now I want to be able to extend this class so i can use the method within it successfully, but obviously do not want to add the function within the vendor directory as this is undesirable. So I have created the following class:

app/lib/Helpers/AppRobots.php

and this has the following contents:

<?php
use Healey\Robots\Robots;
class AppRobots extends Robots {

    /**
     * Add crawl Delay to robots.txt.
     *
     * @param string $delay
     */
    public function crawlDelay($delay)
    {
        $this->addLine("Crawl-delay: $delay");
    }

}

Now in routes.php I have the following:

Route::get('robots.txt', function() {
    // If on the live server, serve a nice, welcoming robots.txt.
    if (App::environment() == 'production')
    {
        \Robots::addUserAgent('*');
        \AppRobots::crawlDelay('3600');

    } else {
        // If you're on any other server, tell everyone to go away.
        \Robots::addDisallow('*');
    }
    return Response::make(Robots::generate(), 200, array('Content-Type' => 'text/plain'));
});

Now this throws the following error:

Non-static method AppRobots::crawlDelay() should not be called statically

So i've changed the method to static as follows:

public static function crawlDelay($delay)
{
    $this->addLine("Crawl-delay: $delay");
}

However this then throws the following error:

Using $this when not in object context so I updated this to use the following method:

/**
 * Add crawl Delay to robots.txt.
 *
 * @param string $delay
 */
public static function crawlDelay($delay)
{
    $robots = new \Robots();
    $robots->addLine("Crawl-delay: $delay");
}

and now I get Call to undefined method Healey\Robots\RobotsFacade::addLine()

This is the RobotsFacade file (vendor/healey/robots/src/Healey/Robots/RobotsFacade.php)

<?php namespace Healey\Robots;

use Illuminate\Support\Facades\Facade;

class RobotsFacade extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'robots'; }
}

and this is the service provider (vendor/healey/robots/src/Healey/Robots/RobotsServiceProvider.php)

<?php namespace Healey\Robots;

use Illuminate\Support\ServiceProvider;

class RobotsServiceProvider extends ServiceProvider
{
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;

    /**
     * Bootstrap the application events.
     *
     * @return void
     */
    public function boot()
    {
        $this->package('healey/robots');
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app['robots'] = $this->app->share(function($app)
        {
            return new Robots();
        });

        $this->app->booting(function()
        {
            $loader = \Illuminate\Foundation\AliasLoader::getInstance();
            $loader->alias('Robots', 'Healey\Robots\RobotsFacade');
        });
    }

}

Any ideas how I can successfuly extend this class so I can add an additional method as required?

update

app/lib/CustomRobotsServiceProvider.php

<?php 
namespace MyApp\Healey\Robots;
use Illuminate\Support\ServiceProvider;
class CustomRobotsServiceProvider extends ServiceProvider
{
  public function boot()
  {
  }

  public function register()
  {
    $this->app['robots'] = $this->app->share(function($app)
    {
        return new AppRobots();
    });
  }
}

app/lib/Helpers/AppRobots.php

<?php
namespace MyApp\Healey\Robots;
use MyApp\Healey\Robots\CustomRobotsServiceProvider;
use Healey\Robots\Robots as Robots;
class AppRobots extends Robots {

    /**
     * Add crawl Delay to robots.txt.
     *
     * @param string $delay
     */
    public static function crawlDelay($delay)
    {
        $robot = new Robots();
        $robot->addLine("Crawl-delay: $delay");
    }

}

app.php in the providers array, I have the following:

    'Healey\Robots\RobotsServiceProvider',
    'MyApp\Healey\Robots\CustomRobotsServiceProvider'

in the aliases array I have the following:

     'Robots'         => 'Healey\Robots\Robots',

However this is not adding the Crawl Delay line using this method:

        \Robots::crawlDelay('3600');

Any ideas why this line isn't been written to the robots.txt route? It is reaching the method fine but not successfully adding this line.

like image 919
GSG Avatar asked Jul 15 '15 16:07

GSG


People also ask

Where is vendor file in laravel?

The vendor is a subfolder in the Laravel root directory. It includes the Composer dependencies in the file autoload. php.


1 Answers

You'll need to create your own service provider and overwrite the "robots" service there so that it uses your class, not the base one.

  1. Create a service provider

    use Illuminate\Support\ServiceProvider;
    class CustomRobotsServiceProvider extends ServiceProvider
    {
      public function boot()
      {
      }
    
      public function register()
      {
        $this->app['robots'] = $this->app->share(function($app)
        {
            return new AppRobots();
        });
      }
    }
    
  2. Register service provider in your config/app.php

    'providers' => array(
       ... some other providers
       'Your\Namespace\CustomRobotsServiceProvider'
    ),
    

Make sure your provider is registered after the RobotsServiceProvider so that your service overwrites the original one, not vice versa.

like image 154
jedrzej.kurylo Avatar answered Oct 25 '22 16:10

jedrzej.kurylo