Вход Регистрация
Файл: vendor/laravel/framework/src/Illuminate/Mail/Mailable.php
Строк: 1656
<?php

namespace IlluminateMail;

use 
IlluminateConfigRepository as ConfigRepository;
use 
IlluminateContainerContainer;
use 
IlluminateContractsFilesystemFactory as FilesystemFactory;
use 
IlluminateContractsMailAttachable;
use 
IlluminateContractsMailFactory as MailFactory;
use 
IlluminateContractsMailMailable as MailableContract;
use 
IlluminateContractsQueueFactory as Queue;
use 
IlluminateContractsSupportHtmlable;
use 
IlluminateContractsSupportRenderable;
use 
IlluminateContractsTranslationHasLocalePreference;
use 
IlluminateSupportCollection;
use 
IlluminateSupportHtmlString;
use 
IlluminateSupportStr;
use 
IlluminateSupportTraitsConditionable;
use 
IlluminateSupportTraitsForwardsCalls;
use 
IlluminateSupportTraitsLocalizable;
use 
IlluminateSupportTraitsMacroable;
use 
IlluminateTestingConstraintsSeeInOrder;
use 
PHPUnitFrameworkAssert as PHPUnit;
use 
ReflectionClass;
use 
ReflectionProperty;
use 
SymfonyComponentMailerHeaderMetadataHeader;
use 
SymfonyComponentMailerHeaderTagHeader;
use 
SymfonyComponentMimeAddress;

class 
Mailable implements MailableContractRenderable
{
    use 
ConditionableForwardsCallsLocalizableMacroable {
        
__call as macroCall;
    }

    
/**
     * The locale of the message.
     *
     * @var string
     */
    
public $locale;

    
/**
     * The person the message is from.
     *
     * @var array
     */
    
public $from = [];

    
/**
     * The "to" recipients of the message.
     *
     * @var array
     */
    
public $to = [];

    
/**
     * The "cc" recipients of the message.
     *
     * @var array
     */
    
public $cc = [];

    
/**
     * The "bcc" recipients of the message.
     *
     * @var array
     */
    
public $bcc = [];

    
/**
     * The "reply to" recipients of the message.
     *
     * @var array
     */
    
public $replyTo = [];

    
/**
     * The subject of the message.
     *
     * @var string
     */
    
public $subject;

    
/**
     * The Markdown template for the message (if applicable).
     *
     * @var string
     */
    
public $markdown;

    
/**
     * The HTML to use for the message.
     *
     * @var string
     */
    
protected $html;

    
/**
     * The view to use for the message.
     *
     * @var string
     */
    
public $view;

    
/**
     * The plain text view to use for the message.
     *
     * @var string
     */
    
public $textView;

    
/**
     * The view data for the message.
     *
     * @var array
     */
    
public $viewData = [];

    
/**
     * The attachments for the message.
     *
     * @var array
     */
    
public $attachments = [];

    
/**
     * The raw attachments for the message.
     *
     * @var array
     */
    
public $rawAttachments = [];

    
/**
     * The attachments from a storage disk.
     *
     * @var array
     */
    
public $diskAttachments = [];

    
/**
     * The tags for the message.
     *
     * @var array
     */
    
protected $tags = [];

    
/**
     * The metadata for the message.
     *
     * @var array
     */
    
protected $metadata = [];

    
/**
     * The callbacks for the message.
     *
     * @var array
     */
    
public $callbacks = [];

    
/**
     * The name of the theme that should be used when formatting the message.
     *
     * @var string|null
     */
    
public $theme;

    
/**
     * The name of the mailer that should send the message.
     *
     * @var string
     */
    
public $mailer;

    
/**
     * The rendered mailable views for testing / assertions.
     *
     * @var array
     */
    
protected $assertionableRenderStrings;

    
/**
     * The callback that should be invoked while building the view data.
     *
     * @var callable
     */
    
public static $viewDataCallback;

    
/**
     * Send the message using the given mailer.
     *
     * @param  IlluminateContractsMailFactory|IlluminateContractsMailMailer  $mailer
     * @return IlluminateMailSentMessage|null
     */
    
public function send($mailer)
    {
        return 
$this->withLocale($this->locale, function () use ($mailer) {
            
$this->prepareMailableForDelivery();

            
$mailer $mailer instanceof MailFactory
                            
$mailer->mailer($this->mailer)
                            : 
$mailer;

            return 
$mailer->send($this->buildView(), $this->buildViewData(), function ($message) {
                
$this->buildFrom($message)
                     ->
buildRecipients($message)
                     ->
buildSubject($message)
                     ->
buildTags($message)
                     ->
buildMetadata($message)
                     ->
runCallbacks($message)
                     ->
buildAttachments($message);
            });
        });
    }

    
/**
     * Queue the message for sending.
     *
     * @param  IlluminateContractsQueueFactory  $queue
     * @return mixed
     */
    
public function queue(Queue $queue)
    {
        if (isset(
$this->delay)) {
            return 
$this->later($this->delay$queue);
        }

        
$connection property_exists($this'connection') ? $this->connection null;

        
$queueName property_exists($this'queue') ? $this->queue null;

        return 
$queue->connection($connection)->pushOn(
            
$queueName ?: null$this->newQueuedJob()
        );
    }

    
/**
     * Deliver the queued message after (n) seconds.
     *
     * @param  DateTimeInterface|DateInterval|int  $delay
     * @param  IlluminateContractsQueueFactory  $queue
     * @return mixed
     */
    
public function later($delayQueue $queue)
    {
        
$connection property_exists($this'connection') ? $this->connection null;

        
$queueName property_exists($this'queue') ? $this->queue null;

        return 
$queue->connection($connection)->laterOn(
            
$queueName ?: null$delay$this->newQueuedJob()
        );
    }

    
/**
     * Make the queued mailable job instance.
     *
     * @return mixed
     */
    
protected function newQueuedJob()
    {
        return 
Container::getInstance()->make(SendQueuedMailable::class, ['mailable' => $this])
                    ->
through(array_merge(
                        
method_exists($this'middleware') ? $this->middleware() : [],
                        
$this->middleware ?? []
                    ));
    }

    
/**
     * Render the mailable into a view.
     *
     * @return string
     *
     * @throws ReflectionException
     */
    
public function render()
    {
        return 
$this->withLocale($this->locale, function () {
            
$this->prepareMailableForDelivery();

            return 
Container::getInstance()->make('mailer')->render(
                
$this->buildView(), $this->buildViewData()
            );
        });
    }

    
/**
     * Build the view for the message.
     *
     * @return array|string
     *
     * @throws ReflectionException
     */
    
protected function buildView()
    {
        if (isset(
$this->html)) {
            return 
array_filter([
                
'html' => new HtmlString($this->html),
                
'text' => $this->textView ?? null,
            ]);
        }

        if (isset(
$this->markdown)) {
            return 
$this->buildMarkdownView();
        }

        if (isset(
$this->view$this->textView)) {
            return [
$this->view$this->textView];
        } elseif (isset(
$this->textView)) {
            return [
'text' => $this->textView];
        }

        return 
$this->view;
    }

    
/**
     * Build the Markdown view for the message.
     *
     * @return array
     *
     * @throws ReflectionException
     */
    
protected function buildMarkdownView()
    {
        
$data $this->buildViewData();

        return [
            
'html' => $this->buildMarkdownHtml($data),
            
'text' => $this->buildMarkdownText($data),
        ];
    }

    
/**
     * Build the view data for the message.
     *
     * @return array
     *
     * @throws ReflectionException
     */
    
public function buildViewData()
    {
        
$data $this->viewData;

        if (static::
$viewDataCallback) {
            
$data array_merge($datacall_user_func(static::$viewDataCallback$this));
        }

        foreach ((new 
ReflectionClass($this))->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
            if (
$property->isInitialized($this) && $property->getDeclaringClass()->getName() !== self::class) {
                
$data[$property->getName()] = $property->getValue($this);
            }
        }

        return 
$data;
    }

    
/**
     * Build the HTML view for a Markdown message.
     *
     * @param  array  $viewData
     * @return Closure
     */
    
protected function buildMarkdownHtml($viewData)
    {
        return 
fn ($data) => $this->markdownRenderer()->render(
            
$this->markdown,
            
array_merge($data$viewData),
        );
    }

    
/**
     * Build the text view for a Markdown message.
     *
     * @param  array  $viewData
     * @return Closure
     */
    
protected function buildMarkdownText($viewData)
    {
        return function (
$data) use ($viewData) {
            if (isset(
$data['message'])) {
                
$data array_merge($data, [
                    
'message' => new TextMessage($data['message']),
                ]);
            }

            return 
$this->textView ?? $this->markdownRenderer()->renderText(
                
$this->markdown,
                
array_merge($data$viewData)
            );
        };
    }

    
/**
     * Resolves a Markdown instance with the mail's theme.
     *
     * @return IlluminateMailMarkdown
     */
    
protected function markdownRenderer()
    {
        return 
tap(Container::getInstance()->make(Markdown::class), function ($markdown) {
            
$markdown->theme($this->theme ?: Container::getInstance()->get(ConfigRepository::class)->get(
                
'mail.markdown.theme''default')
            );
        });
    }

    
/**
     * Add the sender to the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function buildFrom($message)
    {
        if (! empty(
$this->from)) {
            
$message->from($this->from[0]['address'], $this->from[0]['name']);
        }

        return 
$this;
    }

    
/**
     * Add all of the recipients to the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function buildRecipients($message)
    {
        foreach ([
'to''cc''bcc''replyTo'] as $type) {
            foreach (
$this->{$type} as $recipient) {
                
$message->{$type}($recipient['address'], $recipient['name']);
            }
        }

        return 
$this;
    }

    
/**
     * Set the subject for the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function buildSubject($message)
    {
        if (
$this->subject) {
            
$message->subject($this->subject);
        } else {
            
$message->subject(Str::title(Str::snake(class_basename($this), ' ')));
        }

        return 
$this;
    }

    
/**
     * Add all of the attachments to the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function buildAttachments($message)
    {
        foreach (
$this->attachments as $attachment) {
            
$message->attach($attachment['file'], $attachment['options']);
        }

        foreach (
$this->rawAttachments as $attachment) {
            
$message->attachData(
                
$attachment['data'], $attachment['name'], $attachment['options']
            );
        }

        
$this->buildDiskAttachments($message);

        return 
$this;
    }

    
/**
     * Add all of the disk attachments to the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return void
     */
    
protected function buildDiskAttachments($message)
    {
        foreach (
$this->diskAttachments as $attachment) {
            
$storage Container::getInstance()->make(
                
FilesystemFactory::class
            )->
disk($attachment['disk']);

            
$message->attachData(
                
$storage->get($attachment['path']),
                
$attachment['name'] ?? basename($attachment['path']),
                
array_merge(['mime' => $storage->mimeType($attachment['path'])], $attachment['options'])
            );
        }
    }

    
/**
     * Add all defined tags to the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function buildTags($message)
    {
        if (
$this->tags) {
            foreach (
$this->tags as $tag) {
                
$message->getHeaders()->add(new TagHeader($tag));
            }
        }

        return 
$this;
    }

    
/**
     * Add all defined metadata to the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function buildMetadata($message)
    {
        if (
$this->metadata) {
            foreach (
$this->metadata as $key => $value) {
                
$message->getHeaders()->add(new MetadataHeader($key$value));
            }
        }

        return 
$this;
    }

    
/**
     * Run the callbacks for the message.
     *
     * @param  IlluminateMailMessage  $message
     * @return $this
     */
    
protected function runCallbacks($message)
    {
        foreach (
$this->callbacks as $callback) {
            
$callback($message->getSymfonyMessage());
        }

        return 
$this;
    }

    
/**
     * Set the locale of the message.
     *
     * @param  string  $locale
     * @return $this
     */
    
public function locale($locale)
    {
        
$this->locale $locale;

        return 
$this;
    }

    
/**
     * Set the priority of this message.
     *
     * The value is an integer where 1 is the highest priority and 5 is the lowest.
     *
     * @param  int  $level
     * @return $this
     */
    
public function priority($level 3)
    {
        
$this->callbacks[] = function ($message) use ($level) {
            
$message->priority($level);
        };

        return 
$this;
    }

    
/**
     * Set the sender of the message.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function from($address$name null)
    {
        return 
$this->setAddress($address$name'from');
    }

    
/**
     * Determine if the given recipient is set on the mailable.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return bool
     */
    
public function hasFrom($address$name null)
    {
        return 
$this->hasRecipient($address$name'from');
    }

    
/**
     * Set the recipients of the message.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function to($address$name null)
    {
        if (! 
$this->locale && $address instanceof HasLocalePreference) {
            
$this->locale($address->preferredLocale());
        }

        return 
$this->setAddress($address$name'to');
    }

    
/**
     * Determine if the given recipient is set on the mailable.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return bool
     */
    
public function hasTo($address$name null)
    {
        return 
$this->hasRecipient($address$name'to');
    }

    
/**
     * Set the recipients of the message.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function cc($address$name null)
    {
        return 
$this->setAddress($address$name'cc');
    }

    
/**
     * Determine if the given recipient is set on the mailable.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return bool
     */
    
public function hasCc($address$name null)
    {
        return 
$this->hasRecipient($address$name'cc');
    }

    
/**
     * Set the recipients of the message.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function bcc($address$name null)
    {
        return 
$this->setAddress($address$name'bcc');
    }

    
/**
     * Determine if the given recipient is set on the mailable.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return bool
     */
    
public function hasBcc($address$name null)
    {
        return 
$this->hasRecipient($address$name'bcc');
    }

    
/**
     * Set the "reply to" address of the message.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function replyTo($address$name null)
    {
        return 
$this->setAddress($address$name'replyTo');
    }

    
/**
     * Determine if the given replyTo is set on the mailable.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return bool
     */
    
public function hasReplyTo($address$name null)
    {
        return 
$this->hasRecipient($address$name'replyTo');
    }

    
/**
     * Set the recipients of the message.
     *
     * All recipients are stored internally as [['name' => ?, 'address' => ?]]
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @param  string  $property
     * @return $this
     */
    
protected function setAddress($address$name null$property 'to')
    {
        if (empty(
$address)) {
            return 
$this;
        }

        foreach (
$this->addressesToArray($address$name) as $recipient) {
            
$recipient $this->normalizeRecipient($recipient);

            
$this->{$property}[] = [
                
'name' => $recipient->name ?? null,
                
'address' => $recipient->email,
            ];
        }

        
$this->{$property} = collect($this->{$property})
            ->
reverse()
            ->
unique('address')
            ->
reverse()
            ->
values()
            ->
all();

        return 
$this;
    }

    
/**
     * Convert the given recipient arguments to an array.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return array
     */
    
protected function addressesToArray($address$name)
    {
        if (! 
is_array($address) && ! $address instanceof Collection) {
            
$address is_string($name) ? [['name' => $name'email' => $address]] : [$address];
        }

        return 
$address;
    }

    
/**
     * Convert the given recipient into an object.
     *
     * @param  mixed  $recipient
     * @return object
     */
    
protected function normalizeRecipient($recipient)
    {
        if (
is_array($recipient)) {
            if (
array_values($recipient) === $recipient) {
                return (object) 
array_map(function ($email) {
                    return 
compact('email');
                }, 
$recipient);
            }

            return (object) 
$recipient;
        } elseif (
is_string($recipient)) {
            return (object) [
'email' => $recipient];
        } elseif (
$recipient instanceof Address) {
            return (object) [
'email' => $recipient->getAddress(), 'name' => $recipient->getName()];
        } elseif (
$recipient instanceof MailablesAddress) {
            return (object) [
'email' => $recipient->address'name' => $recipient->name];
        }

        return 
$recipient;
    }

    
/**
     * Determine if the given recipient is set on the mailable.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @param  string  $property
     * @return bool
     */
    
protected function hasRecipient($address$name null$property 'to')
    {
        if (empty(
$address)) {
            return 
false;
        }

        
$expected $this->normalizeRecipient(
            
$this->addressesToArray($address$name)[0]
        );

        
$expected = [
            
'name' => $expected->name ?? null,
            
'address' => $expected->email,
        ];

        if (
$this->hasEnvelopeRecipient($expected['address'], $expected['name'], $property)) {
            return 
true;
        }

        return 
collect($this->{$property})->contains(function ($actual) use ($expected) {
            if (! isset(
$expected['name'])) {
                return 
$actual['address'] == $expected['address'];
            }

            return 
$actual == $expected;
        });
    }

    
/**
     * Determine if the mailable "envelope" method defines a recipient.
     *
     * @param  string  $address
     * @param  string|null  $name
     * @param  string  $property
     * @return bool
     */
    
private function hasEnvelopeRecipient($address$name$property)
    {
        return 
method_exists($this'envelope') && match ($property) {
            
'from' => $this->envelope()->isFrom($address$name),
            
'to' => $this->envelope()->hasTo($address$name),
            
'cc' => $this->envelope()->hasCc($address$name),
            
'bcc' => $this->envelope()->hasBcc($address$name),
            
'replyTo' => $this->envelope()->hasReplyTo($address$name),
        };
    }

    
/**
     * Set the subject of the message.
     *
     * @param  string  $subject
     * @return $this
     */
    
public function subject($subject)
    {
        
$this->subject $subject;

        return 
$this;
    }

    
/**
     * Determine if the mailable has the given subject.
     *
     * @param  string  $subject
     * @return bool
     */
    
public function hasSubject($subject)
    {
        return 
$this->subject === $subject ||
               (
method_exists($this'envelope') && $this->envelope()->hasSubject($subject));
    }

    
/**
     * Set the Markdown template for the message.
     *
     * @param  string  $view
     * @param  array  $data
     * @return $this
     */
    
public function markdown($view, array $data = [])
    {
        
$this->markdown $view;
        
$this->viewData array_merge($this->viewData$data);

        return 
$this;
    }

    
/**
     * Set the view and view data for the message.
     *
     * @param  string  $view
     * @param  array  $data
     * @return $this
     */
    
public function view($view, array $data = [])
    {
        
$this->view $view;
        
$this->viewData array_merge($this->viewData$data);

        return 
$this;
    }

    
/**
     * Set the rendered HTML content for the message.
     *
     * @param  string  $html
     * @return $this
     */
    
public function html($html)
    {
        
$this->html $html;

        return 
$this;
    }

    
/**
     * Set the plain text view for the message.
     *
     * @param  string  $textView
     * @param  array  $data
     * @return $this
     */
    
public function text($textView, array $data = [])
    {
        
$this->textView $textView;
        
$this->viewData array_merge($this->viewData$data);

        return 
$this;
    }

    
/**
     * Set the view data for the message.
     *
     * @param  string|array  $key
     * @param  mixed  $value
     * @return $this
     */
    
public function with($key$value null)
    {
        if (
is_array($key)) {
            
$this->viewData array_merge($this->viewData$key);
        } else {
            
$this->viewData[$key] = $value;
        }

        return 
$this;
    }

    
/**
     * Attach a file to the message.
     *
     * @param  string|IlluminateContractsMailAttachable|IlluminateMailAttachment  $file
     * @param  array  $options
     * @return $this
     */
    
public function attach($file, array $options = [])
    {
        if (
$file instanceof Attachable) {
            
$file $file->toMailAttachment();
        }

        if (
$file instanceof Attachment) {
            return 
$file->attachTo($this$options);
        }

        
$this->attachments collect($this->attachments)
                    ->
push(compact('file''options'))
                    ->
unique('file')
                    ->
all();

        return 
$this;
    }

    
/**
     * Attach multiple files to the message.
     *
     * @param  array  $files
     * @return $this
     */
    
public function attachMany($files)
    {
        foreach (
$files as $file => $options) {
            if (
is_int($file)) {
                
$this->attach($options);
            } else {
                
$this->attach($file$options);
            }
        }

        return 
$this;
    }

    
/**
     * Determine if the mailable has the given attachment.
     *
     * @param  string|IlluminateContractsMailAttachable|IlluminateMailAttachment  $file
     * @param  array  $options
     * @return bool
     */
    
public function hasAttachment($file, array $options = [])
    {
        if (
$file instanceof Attachable) {
            
$file $file->toMailAttachment();
        }

        if (
$file instanceof Attachment && $this->hasEnvelopeAttachment($file$options)) {
            return 
true;
        }

        if (
$file instanceof Attachment) {
            
$parts $file->attachWith(
                
fn ($path) => [$path, [
                    
'as' => $options['as'] ?? $file->as,
                    
'mime' => $options['mime'] ?? $file->mime,
                ]],
                
fn ($data) => $this->hasAttachedData($data(), $options['as'] ?? $file->as, ['mime' => $options['mime'] ?? $file->mime])
            );

            if (
$parts === true) {
                return 
true;
            }

            [
$file$options] = $parts === false
                
? [null, []]
                : 
$parts;
        }

        return 
collect($this->attachments)->contains(
            
fn ($attachment) => $attachment['file'] === $file && array_filter($attachment['options']) === array_filter($options)
        );
    }

    
/**
     * Determine if the mailable has the given envelope attachment.
     *
     * @param  IlluminateMailAttachment  $attachment
     * @param  array  $options
     * @return bool
     */
    
private function hasEnvelopeAttachment($attachment$options = [])
    {
        if (! 
method_exists($this'envelope')) {
            return 
false;
        }

        
$attachments $this->attachments();

        return 
Collection::make(is_object($attachments) ? [$attachments] : $attachments)
                ->
map(fn ($attached) => $attached instanceof Attachable $attached->toMailAttachment() : $attached)
                ->
contains(fn ($attached) => $attached->isEquivalent($attachment$options));
    }

    
/**
     * Attach a file to the message from storage.
     *
     * @param  string  $path
     * @param  string|null  $name
     * @param  array  $options
     * @return $this
     */
    
public function attachFromStorage($path$name null, array $options = [])
    {
        return 
$this->attachFromStorageDisk(null$path$name$options);
    }

    
/**
     * Attach a file to the message from storage.
     *
     * @param  string  $disk
     * @param  string  $path
     * @param  string|null  $name
     * @param  array  $options
     * @return $this
     */
    
public function attachFromStorageDisk($disk$path$name null, array $options = [])
    {
        
$this->diskAttachments collect($this->diskAttachments)->push([
            
'disk' => $disk,
            
'path' => $path,
            
'name' => $name ?? basename($path),
            
'options' => $options,
        ])->
unique(function ($file) {
            return 
$file['name'].$file['disk'].$file['path'];
        })->
all();

        return 
$this;
    }

    
/**
     * Determine if the mailable has the given attachment from storage.
     *
     * @param  string  $path
     * @param  string|null  $name
     * @param  array  $options
     * @return bool
     */
    
public function hasAttachmentFromStorage($path$name null, array $options = [])
    {
        return 
$this->hasAttachmentFromStorageDisk(null$path$name$options);
    }

    
/**
     * Determine if the mailable has the given attachment from a specific storage disk.
     *
     * @param  string  $disk
     * @param  string  $path
     * @param  string|null  $name
     * @param  array  $options
     * @return bool
     */
    
public function hasAttachmentFromStorageDisk($disk$path$name null, array $options = [])
    {
        return 
collect($this->diskAttachments)->contains(
            
fn ($attachment) => $attachment['disk'] === $disk
                
&& $attachment['path'] === $path
                
&& $attachment['name'] === ($name ?? basename($path))
                && 
$attachment['options'] === $options
        
);
    }

    
/**
     * Attach in-memory data as an attachment.
     *
     * @param  string  $data
     * @param  string  $name
     * @param  array  $options
     * @return $this
     */
    
public function attachData($data$name, array $options = [])
    {
        
$this->rawAttachments collect($this->rawAttachments)
                ->
push(compact('data''name''options'))
                ->
unique(function ($file) {
                    return 
$file['name'].$file['data'];
                })->
all();

        return 
$this;
    }

    
/**
     * Determine if the mailable has the given data as an attachment.
     *
     * @param  string  $data
     * @param  string  $name
     * @param  array  $options
     * @return bool
     */
    
public function hasAttachedData($data$name, array $options = [])
    {
        return 
collect($this->rawAttachments)->contains(
            
fn ($attachment) => $attachment['data'] === $data
                
&& $attachment['name'] === $name
                
&& array_filter($attachment['options']) === array_filter($options)
        );
    }

    
/**
     * Add a tag header to the message when supported by the underlying transport.
     *
     * @param  string  $value
     * @return $this
     */
    
public function tag($value)
    {
        
array_push($this->tags$value);

        return 
$this;
    }

    
/**
     * Determine if the mailable has the given tag.
     *
     * @param  string  $value
     * @return bool
     */
    
public function hasTag($value)
    {
        return 
in_array($value$this->tags) ||
               (
method_exists($this'envelope') && in_array($value$this->envelope()->tags));
    }

    
/**
     * Add a metadata header to the message when supported by the underlying transport.
     *
     * @param  string  $key
     * @param  string  $value
     * @return $this
     */
    
public function metadata($key$value)
    {
        
$this->metadata[$key] = $value;

        return 
$this;
    }

    
/**
     * Determine if the mailable has the given metadata.
     *
     * @param  string  $key
     * @param  string  $value
     * @return bool
     */
    
public function hasMetadata($key$value)
    {
        return (isset(
$this->metadata[$key]) && $this->metadata[$key] === $value) ||
               (
method_exists($this'envelope') && $this->envelope()->hasMetadata($key$value));
    }

    
/**
     * Assert that the mailable is from the given address.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function assertFrom($address$name null)
    {
        
$this->renderForAssertions();

        
$recipient $this->formatAssertionRecipient($address$name);

        
PHPUnit::assertTrue(
            
$this->hasFrom($address$name),
            
"Email was not from expected address [{$recipient}]."
        
);

        return 
$this;
    }

    
/**
     * Assert that the mailable has the given recipient.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function assertTo($address$name null)
    {
        
$this->renderForAssertions();

        
$recipient $this->formatAssertionRecipient($address$name);

        
PHPUnit::assertTrue(
            
$this->hasTo($address$name),
            
"Did not see expected recipient [{$recipient}] in email 'to' recipients."
        
);

        return 
$this;
    }

    
/**
     * Assert that the mailable has the given recipient.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function assertHasTo($address$name null)
    {
        return 
$this->assertTo($address$name);
    }

    
/**
     * Assert that the mailable has the given recipient.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function assertHasCc($address$name null)
    {
        
$this->renderForAssertions();

        
$recipient $this->formatAssertionRecipient($address$name);

        
PHPUnit::assertTrue(
            
$this->hasCc($address$name),
            
"Did not see expected recipient [{$recipient}] in email 'cc' recipients."
        
);

        return 
$this;
    }

    
/**
     * Assert that the mailable has the given recipient.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function assertHasBcc($address$name null)
    {
        
$this->renderForAssertions();

        
$recipient $this->formatAssertionRecipient($address$name);

        
PHPUnit::assertTrue(
            
$this->hasBcc($address$name),
            
"Did not see expected recipient [{$recipient}] in email 'bcc' recipients."
        
);

        return 
$this;
    }

    
/**
     * Assert that the mailable has the given "reply to" address.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return $this
     */
    
public function assertHasReplyTo($address$name null)
    {
        
$this->renderForAssertions();

        
$replyTo $this->formatAssertionRecipient($address$name);

        
PHPUnit::assertTrue(
            
$this->hasReplyTo($address$name),
            
"Did not see expected address [{$replyTo}] as email 'reply to' recipient."
        
);

        return 
$this;
    }

    
/**
     * Format the mailable recipient for display in an assertion message.
     *
     * @param  object|array|string  $address
     * @param  string|null  $name
     * @return string
     */
    
private function formatAssertionRecipient($address$name null)
    {
        if (! 
is_string($address)) {
            
$address json_encode($address);
        }

        if (
filled($name)) {
            
$address .= ' ('.$name.')';
        }

        return 
$address;
    }

    
/**
     * Assert that the mailable has the given subject.
     *
     * @param  string  $subject
     * @return $this
     */
    
public function assertHasSubject($subject)
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasSubject($subject),
            
"Did not see expected text [{$subject}] in email subject."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given text is present in the HTML email body.
     *
     * @param  string  $string
     * @param  bool  $escape
     * @return $this
     */
    
public function assertSeeInHtml($string$escape true)
    {
        
$string $escape e($string) : $string;

        [
$html$text] = $this->renderForAssertions();

        
PHPUnit::assertStringContainsString(
            
$string,
            
$html,
            
"Did not see expected text [{$string}] within email body."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given text is not present in the HTML email body.
     *
     * @param  string  $string
     * @param  bool  $escape
     * @return $this
     */
    
public function assertDontSeeInHtml($string$escape true)
    {
        
$string $escape e($string) : $string;

        [
$html$text] = $this->renderForAssertions();

        
PHPUnit::assertStringNotContainsString(
            
$string,
            
$html,
            
"Saw unexpected text [{$string}] within email body."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given text strings are present in order in the HTML email body.
     *
     * @param  array  $strings
     * @param  bool  $escape
     * @return $this
     */
    
public function assertSeeInOrderInHtml($strings$escape true)
    {
        
$strings $escape array_map('e'$strings) : $strings;

        [
$html$text] = $this->renderForAssertions();

        
PHPUnit::assertThat($strings, new SeeInOrder($html));

        return 
$this;
    }

    
/**
     * Assert that the given text is present in the plain-text email body.
     *
     * @param  string  $string
     * @return $this
     */
    
public function assertSeeInText($string)
    {
        [
$html$text] = $this->renderForAssertions();

        
PHPUnit::assertStringContainsString(
            
$string,
            
$text,
            
"Did not see expected text [{$string}] within text email body."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given text is not present in the plain-text email body.
     *
     * @param  string  $string
     * @return $this
     */
    
public function assertDontSeeInText($string)
    {
        [
$html$text] = $this->renderForAssertions();

        
PHPUnit::assertStringNotContainsString(
            
$string,
            
$text,
            
"Saw unexpected text [{$string}] within text email body."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given text strings are present in order in the plain-text email body.
     *
     * @param  array  $strings
     * @return $this
     */
    
public function assertSeeInOrderInText($strings)
    {
        [
$html$text] = $this->renderForAssertions();

        
PHPUnit::assertThat($strings, new SeeInOrder($text));

        return 
$this;
    }

    
/**
     * Assert the mailable has the given attachment.
     *
     * @param  string|IlluminateContractsMailAttachable|IlluminateMailAttachment  $file
     * @param  array  $options
     * @return $this
     */
    
public function assertHasAttachment($file, array $options = [])
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasAttachment($file$options),
            
'Did not find the expected attachment.'
        
);

        return 
$this;
    }

    
/**
     * Assert the mailable has the given data as an attachment.
     *
     * @param  string  $data
     * @param  string  $name
     * @param  array  $options
     * @return $this
     */
    
public function assertHasAttachedData($data$name, array $options = [])
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasAttachedData($data$name$options),
            
'Did not find the expected attachment.'
        
);

        return 
$this;
    }

    
/**
     * Assert the mailable has the given attachment from storage.
     *
     * @param  string  $path
     * @param  string|null  $name
     * @param  array  $options
     * @return $this
     */
    
public function assertHasAttachmentFromStorage($path$name null, array $options = [])
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasAttachmentFromStorage($path$name$options),
            
'Did not find the expected attachment.'
        
);

        return 
$this;
    }

    
/**
     * Assert the mailable has the given attachment from a specific storage disk.
     *
     * @param  string  $disk
     * @param  string  $path
     * @param  string|null  $name
     * @param  array  $options
     * @return $this
     */
    
public function assertHasAttachmentFromStorageDisk($disk$path$name null, array $options = [])
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasAttachmentFromStorageDisk($disk$path$name$options),
            
'Did not find the expected attachment.'
        
);

        return 
$this;
    }

    
/**
     * Assert that the mailable has the given tag.
     *
     * @param  string  $tag
     * @return $this
     */
    
public function assertHasTag($tag)
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasTag($tag),
            
"Did not see expected tag [{$tag}] in email tags."
        
);

        return 
$this;
    }

    
/**
     * Assert that the mailable has the given metadata.
     *
     * @param  string  $key
     * @param  string  $value
     * @return $this
     */
    
public function assertHasMetadata($key$value)
    {
        
$this->renderForAssertions();

        
PHPUnit::assertTrue(
            
$this->hasMetadata($key$value),
            
"Did not see expected key [{$key}] and value [{$value}] in email metadata."
        
);

        return 
$this;
    }

    
/**
     * Render the HTML and plain-text version of the mailable into views for assertions.
     *
     * @return array
     *
     * @throws ReflectionException
     */
    
protected function renderForAssertions()
    {
        if (
$this->assertionableRenderStrings) {
            return 
$this->assertionableRenderStrings;
        }

        return 
$this->assertionableRenderStrings $this->withLocale($this->locale, function () {
            
$this->prepareMailableForDelivery();

            
$html Container::getInstance()->make('mailer')->render(
                
$view $this->buildView(), $this->buildViewData()
            );

            if (
is_array($view) && isset($view[1])) {
                
$text $view[1];
            }

            
$text ??= $view['text'] ?? '';

            if (! empty(
$text) && ! $text instanceof Htmlable) {
                
$text Container::getInstance()->make('mailer')->render(
                    
$text$this->buildViewData()
                );
            }

            return [(string) 
$html, (string) $text];
        });
    }

    
/**
     * Prepare the mailable instance for delivery.
     *
     * @return void
     */
    
protected function prepareMailableForDelivery()
    {
        if (
method_exists($this'build')) {
            
Container::getInstance()->call([$this'build']);
        }

        
$this->ensureHeadersAreHydrated();
        
$this->ensureEnvelopeIsHydrated();
        
$this->ensureContentIsHydrated();
        
$this->ensureAttachmentsAreHydrated();
    }

    
/**
     * Ensure the mailable's headers are hydrated from the "headers" method.
     *
     * @return void
     */
    
private function ensureHeadersAreHydrated()
    {
        if (! 
method_exists($this'headers')) {
            return;
        }

        
$headers $this->headers();

        
$this->withSymfonyMessage(function ($message) use ($headers) {
            if (
$headers->messageId) {
                
$message->getHeaders()->addIdHeader('Message-Id'$headers->messageId);
            }

            if (
count($headers->references) > 0) {
                
$message->getHeaders()->addTextHeader('References'$headers->referencesString());
            }

            foreach (
$headers->text as $key => $value) {
                
$message->getHeaders()->addTextHeader($key$value);
            }
        });
    }

    
/**
     * Ensure the mailable's "envelope" data is hydrated from the "envelope" method.
     *
     * @return void
     */
    
private function ensureEnvelopeIsHydrated()
    {
        if (! 
method_exists($this'envelope')) {
            return;
        }

        
$envelope $this->envelope();

        if (isset(
$envelope->from)) {
            
$this->from($envelope->from->address$envelope->from->name);
        }

        foreach ([
'to''cc''bcc''replyTo'] as $type) {
            foreach (
$envelope->{$type} as $address) {
                
$this->{$type}($address->address$address->name);
            }
        }

        if (
$envelope->subject) {
            
$this->subject($envelope->subject);
        }

        foreach (
$envelope->tags as $tag) {
            
$this->tag($tag);
        }

        foreach (
$envelope->metadata as $key => $value) {
            
$this->metadata($key$value);
        }

        foreach (
$envelope->using as $callback) {
            
$this->withSymfonyMessage($callback);
        }
    }

    
/**
     * Ensure the mailable's content is hydrated from the "content" method.
     *
     * @return void
     */
    
private function ensureContentIsHydrated()
    {
        if (! 
method_exists($this'content')) {
            return;
        }

        
$content $this->content();

        if (
$content->view) {
            
$this->view($content->view);
        }

        if (
$content->html) {
            
$this->view($content->html);
        }

        if (
$content->text) {
            
$this->text($content->text);
        }

        if (
$content->markdown) {
            
$this->markdown($content->markdown);
        }

        if (
$content->htmlString) {
            
$this->html($content->htmlString);
        }

        foreach (
$content->with as $key => $value) {
            
$this->with($key$value);
        }
    }

    
/**
     * Ensure the mailable's attachments are hydrated from the "attachments" method.
     *
     * @return void
     */
    
private function ensureAttachmentsAreHydrated()
    {
        if (! 
method_exists($this'attachments')) {
            return;
        }

        
$attachments $this->attachments();

        
Collection::make(is_object($attachments) ? [$attachments] : $attachments)
            ->
each(function ($attachment) {
                
$this->attach($attachment);
            });
    }

    
/**
     * Set the name of the mailer that should send the message.
     *
     * @param  string  $mailer
     * @return $this
     */
    
public function mailer($mailer)
    {
        
$this->mailer $mailer;

        return 
$this;
    }

    
/**
     * Register a callback to be called with the Symfony message instance.
     *
     * @param  callable  $callback
     * @return $this
     */
    
public function withSymfonyMessage($callback)
    {
        
$this->callbacks[] = $callback;

        return 
$this;
    }

    
/**
     * Register a callback to be called while building the view data.
     *
     * @param  callable  $callback
     * @return void
     */
    
public static function buildViewDataUsing(callable $callback)
    {
        static::
$viewDataCallback $callback;
    }

    
/**
     * Dynamically bind parameters to the message.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return $this
     *
     * @throws BadMethodCallException
     */
    
public function __call($method$parameters)
    {
        if (static::
hasMacro($method)) {
            return 
$this->macroCall($method$parameters);
        }

        if (
str_starts_with($method'with')) {
            return 
$this->with(Str::camel(substr($method4)), $parameters[0]);
        }

        static::
throwBadMethodCallException($method);
    }
}
Онлайн: 0
Реклама