简体   繁体   中英

Processwire/API hook (PHP function inside a function)

I'm writing a hook using the ProcessWire API... pretty common practice with it's powerful API.

The below works completely fine...

$this->addHookAfter('Pages::saved', function(HookEvent $event) {

    $arguments = $event->arguments();
    $page = $event->arguments(0);

    if ($page->template == 'user') {

        // Require relevent libraries
        require_once($this->config->paths->root . 'api/sendgrid/sendgrid-php.php');

        // SendGrid API init
        $sgAPIKey = "XXXX";

        // Set email confirmation settings
        $email_admin = 'test@example.com';
        $email_customer = $page->email;
        $email_admin_subject = "You added a new user $page->name";
        $email_customer_subject = 'Your login details';

        $from = new \SendGrid\Email("Example User", $email_admin);
        $subject = "Sending with SendGrid is Fun";
        $to = new \SendGrid\Email("Example User", $email_customer);
        $content = new \SendGrid\Content("text/plain", "and easy to do anywhere, even with PHP");
        $mail = new \SendGrid\Mail($from, $subject, $to, $content);

        $sg = new \SendGrid($sgAPIKey);
        $response = $sg->client->mail()->send()->post($mail);

        // Dump SendGrid object with TracyDebugger
        bd($mail);
    }

});

However, as soon as I add a function to send the email (in order to set up two separate send mail functions (one to admin, one to customer) it doesn't work at all. No errors... just $mail returns NULL.

$this->addHookAfter('Pages::saved', function(HookEvent $event) {

    $arguments = $event->arguments();
    $page = $event->arguments(0);

    if ($page->template == 'user') {

        // Require relevent libraries
        require_once($this->config->paths->root . 'api/sendgrid/sendgrid-php.php');

        // SendGrid API init
        $sgAPIKey = "XXXX";
        // Set email confirmation settings
        $email_admin = 'test@example.com';
        $email_customer = $page->email;
        $email_admin_subject = "You added a new user $page->name";
        $email_customer_subject = 'Your login details';
        $email_customer_body = 'This is a test';

        function send_email($from_email, $to_email, $subject, $body) {
            global $sgAPIKey;
            $from = new \SendGrid\Email(null, $from_email);
            $to = new \SendGrid\Email(null, $to_email);
            $content = new \SendGrid\Content("text/html", $body);
            $mail = new \SendGrid\Mail($from, $subject, $to, $content);
            $sg = new \SendGrid($sgAPIKey);
            $response = $sg->client->mail()->send()->post($mail);
        }

        send_email($email_admin, $email_customer, $email_customer_subject, $email_customer_body);

        // Dump SendGrid object with TracyDebugger
        global $mail;
        bd($mail);
    }

});

Is there any reason why a function like this wouldn't work? Is it because technically there's a function inside a function? I would've at least have thought it would've returned an error.

Functions inside of functions are allowed in PHP, however the issue that you are experiencing is more of an issue with scoping. $mail is no longer in scope after that function is completed, meaning, among other things, that you can no longer access that variable.

One possible solution is to return that variable when the function completes, like so:

function send_email($from_email, $to_email, $subject, $body) {
        global $sgAPIKey;
        $from = new \SendGrid\Email(null, $from_email);
        $to = new \SendGrid\Email(null, $to_email);
        $content = new \SendGrid\Content("text/html", $body);
        $mail = new \SendGrid\Mail($from, $subject, $to, $content);
        $sg = new \SendGrid($sgAPIKey);
        $response = $sg->client->mail()->send()->post($mail);
        return $mail;
}

That way, when you execute the function, you can set it to a variable.

As an aside, I noticed you attempted to use the global keyword to access that $mail variable. Not only is that typically frowned upon as bad practice, it would never work in this context. The global keyword is used to make variables that are in the global namespace accessable. The typical use is as follows:

$global_variable = "foobar";
class Foo {
  public static function test() {
    return $global_variable;
  }
  public static function test_two() {
    global $global_variable;
    return $global_variable;
  }
}
echo(Foo::test()); //echoes nothing, since in scope, the variable is not set
echo(Foo::test_two()); //echoes 'foobar', since we told PHP to put it in scope

TLDR: The global keyword makes variables that are in the global scope, be visible in the local scope.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM