laravel-shift/blueprint

Support for multiple `send` key items for controllers

Closed this issue · 10 comments

Synopsis:

Allow specifying multiple items for the send key to send multiple notifications.

Proposed Syntax:

Ticket:
  resource: all
  store:
    validate: title, content
    save: ticket
    send:
      - TicketReceived to:ticket.customer with:ticket
      - NewTicket to:ticket.staff with:ticket
    dispatch: SyncMedia with:ticket
    fire: NewTicket with:ticket
    flash: ticket.id
    redirect: ticket.index

Expected Behavior:

The proposed syntax should generate multiple lines.

Notification::send($ticket->customer, new TicketReceived($ticket));
Notification::send($ticket->staff, new NewTicket($ticket));

I think the way to do this would be:

send: TicketReceived to:ticket.customer with:ticket
send: NewTicket to:ticket.staff with:ticket

Same amount of keystrokes really. But let me know if that doesn't work.

That currently fails since duplicate keys are not supported in YAML nor JSON.

php artisan blueprint:build

   Symfony\Component\Yaml\Exception\ParseException

  Duplicate key "send" detected at line 538 (near "send: A to:ticket.author with:ticket").

  at vendor/symfony/yaml/Parser.php:348
    344▕                     // But overwriting is allowed when a merge node is used in current block.
    345▕                     if ($allowOverwrite || !isset($data[$key])) {
    346▕                         $data[$key] = $value;
    347▕                     } else {
  ➜ 348▕                         throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
    349▕                     }
    350▕                 }
    351▕                 if ($isRef) {
    352▕                     $this->refs[$isRef] = $data[$key];

Ah, lame YAML. I have reopened this for the community to implement.

Will take a look in the next days and see if I can figure out where to get the additional parsing working 👀

I'd probably look at the Statement "lexer". I believe there is where you could check and handle if the value is an array, if so, register multiple SendStatement. The rest should just work.

Just had a cursory look and due to how the parser seems to work it results in something like this for a send array

      "store" => array:7 [
        "validate" => "title, content"
        "save" => "ticket"
        "send" => "ReviewNotification to:ticket.author with:ticket ReviewNotification to:ticket.author with:ticket"
        "dispatch" => "SyncMedia with:ticket"
        "fire" => "NewTicket with:ticket"
        "flash" => "ticket.id"
        "redirect" => "ticket.index"
      ]

I'll have a proper look when I'm at my machine.

Edit:

This is happening due to this part.

        if ($strip_dashes) {
            $content = preg_replace('/^(\s*)-\s*/m', '\1', $content);
        }

Removing gets the array working.

@jasonmccreary what was the problem that required strip_dashes? This effectively makes it impossible to use arrays in the draft.yml file since those array items are usually denoted by a leading dash. An alternative would be to use the [] syntax, see https://www.w3schools.io/file/yaml-arrays/.

Ticket:
  resource: all
  store:
    validate: title, content
    save: ticket
    send: [
      TicketReceived to:ticket.customer with:ticket,
      NewTicket to:ticket.staff with:ticket
    ]
    dispatch: SyncMedia with:ticket
    fire: NewTicket with:ticket
    flash: ticket.id
    redirect: ticket.index

Try with just an indent, no brackets, no dashes.

Doesn't work like that since that isn't valid YAML. Summary from what I've gathered so far:

  • The $strip_dashes flag makes the most common way of declaring arrays impossible.
  • The ControllerGenerator class would need to be modified but to handle arrays but this can be easily handled by adding foreach (Arr::wrap($statement) as $statement).
  • The same applies to the StatementLexer class.

Closed by #623.