Emmanuel-Ab
Emmanuel-Ab

Reputation: 331

I am trying to write a custom Laravel function on boot, but I get errors

So I am trying to write the following function in the App Service Provider but am getting errors:

My code is:

public function boot()
{
    $homepage = 'https://example.com';
    $already_crawled = [];
    $crawling = [];

    function follow_links($url)
    {
        global $already_crawled;
        global $crawling;

        $doc = new \DOMDocument();
        $doc->loadHTML(file_get_contents($url));

        $linklist = $doc->getElementsByTagName('a');

        foreach ($linklist as $link) {
            $l = $link->getAttribute("href");
            $full_link = 'https://example.com' . $l;

            if (!in_array($full_link, $already_crawled)) {
                $already_crawled[] = $full_link;
                $crawling[] = $full_link;
                Log::info($full_link . PHP_EOL);
            }
        }

        array_shift($crawling);
        foreach ($crawling as $link) {
            follow_links($link);
        }
    }

    follow_links($homepage);
}

So with this code I am getting errors like:

in_array() expected parameter 2 to be array, null given

What should I do to run this without problems?

Upvotes: 0

Views: 62

Answers (1)

ceejayoz
ceejayoz

Reputation: 180024

Your variables in your boot function aren't global, so your follow_links function's globals are a totally separate set of variables. You should basically never have the keyword global anywhere in Laravel, ever.

Because of your scope issues, $already_crawled is undefined when you first attempt to feed it to is_array. Use class properties, and $this to access them. On top of that, I've removed the weird function-in-a-function construction:

protected $already_crawled;
protected $crawling;
protected $homepage;

public function boot()
{
    $this->homepage = 'https://example.com';
    $this->already_crawled = [];
    $this->crawling = [];

    $this->follow_links($this->homepage);
}

protected function follow_links($url)
{
    $doc = new \DOMDocument();
    $doc->loadHTML(file_get_contents($url));

    $linklist = $doc->getElementsByTagName('a');

    foreach ($linklist as $link) {
        $l = $link->getAttribute("href");
        $full_link = 'https://example.com' . $l;

        if (!in_array($full_link, $this->already_crawled)) {
            $this->already_crawled[] = $full_link;
            $this->crawling[] = $full_link;
            Log::info($full_link . PHP_EOL);
        }
    }

    array_shift($this->crawling);
    foreach ($this->crawling as $link) {
        $this->follow_links($link);
    }
}

Side note: You almost certainly don't want this in your service provider. It's going to make a HTTP file_get_contents call on every single pageview your app ever serves. It's going to slow your app down dramatically.

Upvotes: 1

Related Questions