php - array - ¿Agregar un atributo personalizado a un modelo de Laravel/Eloquent en carga?




toarray laravel (5)

Me gustaría poder agregar un atributo / propiedad personalizado a un modelo de Laravel / Eloquent cuando se carga, de forma similar a cómo se podría lograr con el RedBean's $model->open() RedBean's .

Por ejemplo, en este momento, en mi controlador tengo:

public function index()
{
    $sessions = EventSession::all();
    foreach ($sessions as $i => $session) {
        $sessions[$i]->available = $session->getAvailability();
    }
    return $sessions;
}

Sería bueno poder omitir el bucle y tener el atributo 'disponible' ya configurado y poblado.

He intentado utilizar algunos de los eventos del modelo descritos en la documentación para adjuntar esta propiedad cuando se carga el objeto, pero sin éxito hasta el momento.

Notas:

  • 'disponible' no es un campo en la tabla subyacente.
  • $sessions se devuelve como un objeto JSON como parte de una API y, por lo tanto, llamar a algo como $session->available() en una plantilla no es una opción

El problema está causado por el hecho de que el método toArray() del Model ignora cualquier acceso que no se relacione directamente con una columna en la tabla subyacente.

Como Taylor Otwell mencionó here , "Esto es intencional y por motivos de rendimiento". Sin embargo, hay una manera fácil de lograr esto:

class EventSession extends Eloquent {

    protected $table = 'sessions';
    protected $appends = array('availability');

    public function getAvailabilityAttribute()
    {
        return $this->calculateAvailability();  
    }
}

Cualquier atributo enumerado en la propiedad $ adjuntos se incluirá automáticamente en la matriz o el formulario JSON del modelo, siempre que haya agregado el descriptor de acceso adecuado.

Respuesta anterior (para versiones de Laravel <4.08):

La mejor solución que he encontrado es anular el método toArray() y explicity establecer el atributo:

class Book extends Eloquent {

    protected $table = 'books';

    public function toArray()
    {
        $array = parent::toArray();
        $array['upper'] = $this->upper;
        return $array;
    }

    public function getUpperAttribute()
    {
        return strtoupper($this->title);    
    }

}

o, si tiene muchos accesadores personalizados, recorra todos ellos y aplíquelos:

class Book extends Eloquent {

    protected $table = 'books';

    public function toArray()
    {
        $array = parent::toArray();
        foreach ($this->getMutatedAttributes() as $key)
        {
            if ( ! array_key_exists($key, $array)) {
                $array[$key] = $this->{$key};   
            }
        }
        return $array;
    }

    public function getUpperAttribute()
    {
        return strtoupper($this->title);    
    }

}

En mi modelo de suscripción, necesito saber si la suscripción está pausada o no. así es como lo hice en public function getIsPausedAttribute() { $isPaused = false; if (!$this->is_active) { $isPaused = true; } } public function getIsPausedAttribute() { $isPaused = false; if (!$this->is_active) { $isPaused = true; } }

luego, en la plantilla de vista, puedo usar $subscription->is_paused para obtener el resultado.

El getIsPausedAttribute es el formato para establecer un atributo personalizado,

y usa is_paused para obtener o usar el atributo en su vista.


Si cambia el nombre de su método getAvailability() a getAvailableAttribute() su método se convierte en un acceso y podrá leerlo usando ->available directamente en su modelo.

Documentos: https://laravel.com/docs/5.4/eloquent-mutators#accessors-and-mutators

EDITAR: como su atributo es "virtual", no está incluido por defecto en la representación JSON de su objeto.

Pero encontré esto: ¿ Los accesadores de modelo personalizados no se procesan cuando se llama a> toJson ()?

Para forzar que su atributo sea devuelto en la matriz, agréguelo como una clave para la matriz $ attributes.

class User extends Eloquent {
    protected $attributes = array(
        'ZipCode' => '',
    );

    public function getZipCodeAttribute()
    {
        return ....
    }
}

No lo probé, pero debería ser bastante trivial para que pruebes en tu configuración actual.


Tenía algo simular: tengo una imagen de atributo en mi modelo, esta contiene la ubicación del archivo en la carpeta de Almacenamiento. La imagen debe devolverse codificada en base64

//Add extra attribute
protected $attributes = ['pictureData'];

//Make it available in the json response
protected $appends = ['pictureData'];

//implement the attribute
public function getPictureDataAttribute()
{
    $file = Storage::get($this->picture);
    $type = Storage::mimeType($this->picture);
    return "data:" . $type . ";base64," . base64_encode($file);
}

puede usar la función setAttribute en Model para agregar un atributo personalizado





eloquent