Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Illuminate/Collections/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

use ArrayAccess;
use ArrayIterator;
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
use Illuminate\Support\Traits\EnumeratesValues;
use Illuminate\Support\Traits\Macroable;
use stdClass;

class Collection implements ArrayAccess, Enumerable
class Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerable
{
use EnumeratesValues, Macroable;

Expand Down
3 changes: 2 additions & 1 deletion src/Illuminate/Collections/LazyCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
use ArrayIterator;
use Closure;
use DateTimeInterface;
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
use Illuminate\Support\Traits\EnumeratesValues;
use Illuminate\Support\Traits\Macroable;
use IteratorAggregate;
use stdClass;

class LazyCollection implements Enumerable
class LazyCollection implements CanBeEscapedWhenCastToString, Enumerable
{
use EnumeratesValues, Macroable;

Expand Down
24 changes: 23 additions & 1 deletion src/Illuminate/Collections/Traits/EnumeratesValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
*/
trait EnumeratesValues
{
/**
* Indicates that the object's string representation should be escaped when __toString is invoked.
*
* @var bool
*/
protected $escapeWhenCastingToString = false;

/**
* The methods that can be proxied.
*
Expand Down Expand Up @@ -900,7 +907,22 @@ public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
*/
public function __toString()
{
return $this->toJson();
return $this->escapeWhenCastingToString
? e($this->toJson())
: $this->toJson();
}

/**
* Indicate that the model's string representation should be escaped when __toString is invoked.
*
* @param bool $escape
* @return $this
*/
public function escapeWhenCastingToString($escape = true)
{
$this->escapeWhenCastingToString = $escape;

return $this;
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/Illuminate/Contracts/Support/CanBeEscapedWhenCastToString.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Illuminate\Contracts\Support;

interface CanBeEscapedWhenCastToString
{
/**
* Indicate that the object's string representation should be escaped when __toString is invoked.
*
* @param bool $escape
* @return $this
*/
public function escapeWhenCastingToString($escape = true);
}
27 changes: 25 additions & 2 deletions src/Illuminate/Database/Eloquent/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Database\ConnectionResolverInterface as Resolver;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
Expand All @@ -22,7 +23,7 @@
use JsonSerializable;
use LogicException;

abstract class Model implements Arrayable, ArrayAccess, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
abstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToString, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
use Concerns\HasAttributes,
Concerns\HasEvents,
Expand Down Expand Up @@ -110,6 +111,13 @@ abstract class Model implements Arrayable, ArrayAccess, HasBroadcastChannel, Jso
*/
public $wasRecentlyCreated = false;

/**
* Indicates that the object's string representation should be escaped when __toString is invoked.
*
* @var bool
*/
protected $escapeWhenCastingToString = false;

/**
* The connection resolver instance.
*
Expand Down Expand Up @@ -2128,7 +2136,22 @@ public static function __callStatic($method, $parameters)
*/
public function __toString()
{
return $this->toJson();
return $this->escapeWhenCastingToString
? e($this->toJson())
: $this->toJson();
}

/**
* Indicate that the object's string representation should be escaped when __toString is invoked.
*
* @param bool $escape
* @return $this
*/
public function escapeWhenCastingToString($escape = true)
{
$this->escapeWhenCastingToString = $escape;

return $this;
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/Illuminate/View/Compilers/Concerns/CompilesComponents.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\View\Compilers\Concerns;

use Illuminate\Contracts\Support\CanBeEscapedWhenCastToString;
use Illuminate\Support\Str;
use Illuminate\View\ComponentAttributeBag;

Expand Down Expand Up @@ -183,6 +184,10 @@ protected function compileAware($expression)
*/
public static function sanitizeComponentAttribute($value)
{
if (is_object($value) && $value instanceof CanBeEscapedWhenCastToString) {
return $value->escapeWhenCastingToString();
}

return is_string($value) ||
(is_object($value) && ! $value instanceof ComponentAttributeBag && method_exists($value, '__toString'))
? e($value)
Expand Down
4 changes: 4 additions & 0 deletions tests/View/Blade/BladeComponentTagCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\View\Compilers\BladeCompiler;
use Illuminate\View\Compilers\ComponentTagCompiler;
use Illuminate\View\Component;
Expand Down Expand Up @@ -291,10 +292,13 @@ public function __toString()
}
};

$model = new class extends Model {};

$this->assertEquals(e('<hi>'), BladeCompiler::sanitizeComponentAttribute('<hi>'));
$this->assertEquals(e('1'), BladeCompiler::sanitizeComponentAttribute('1'));
$this->assertEquals(1, BladeCompiler::sanitizeComponentAttribute(1));
$this->assertEquals(e('<hi>'), BladeCompiler::sanitizeComponentAttribute($class));
$this->assertSame($model, BladeCompiler::sanitizeComponentAttribute($model));
}

public function testItThrowsAnExceptionForNonExistingAliases()
Expand Down