it-swarm.com.de

Leere Zeichenfolge anstelle von Nullwerten Eloquent

Ich versuche, Entitäten mit der Eloquent-Funktion "Massenzuweisung" zu erstellen ...

$new = new Contact(Input::all());
$new->save();

Das Problem ist, dass auf diese Weise jedes Feld wie erwartet mit einer leeren Zeichenfolge anstelle von null-Werten ausgefüllt wird.

Ich entwickle gerade das System und einige Tabellenspalten sind noch nicht definiert. Aus diesem Grund sollten Sie diese Methode verwenden, um zu vermeiden, dass jedes neue Feld zu $fillable-Array und zu einem new Contact(array(...));... hinzugefügt wird.

Ich habe auch ungefähr 20 Felder in dieser Tabelle, daher wäre es etwas hässlich, ein Array wie

$new = new Contact(array(
    'salutation' => Input::get('salutation'),
    'first_name' => Input::get('first_name'),
    'last_name'  => Input::get('last_name'),
    'company_id' => Input::get('company_id'),
    'city' => ...
    ...
));

Irgendwelche Tipps, wie man das macht oder repariert?

Update Inzwischen habe ich das mit dem array_filter im App::before()-Filter erledigt.

Update Im Filter war ein bisschen Chaos. Am Ende mache ich:

public static function allEmptyIdsToNull()
{
    $input = Input::all();

    $result = preg_grep_keys ( '/_id$/' , $input );

    $nulledResults = array_map(function($item) {
        if (empty($item))
            return null;

        return $item;
    }, $result);

    return array_merge($input, $nulledResults);
}

Und in meinen Funktionen.php.

if ( ! function_exists('preg_grep_keys'))
{
    /**
    * This function gets does the same as preg_grep but applies the regex
    * to the array keys instead to the array values as this last does.
    * Returns an array containing only the keys that match the exp.
    * 
    * @author Daniel Klein
    * 
    * @param  string  $pattern
    * @param  array  $input
    * @param  integer $flags
    * @return array
    */
    function preg_grep_keys($pattern, array $input, $flags = 0) {
        return array_intersect_key($input, array_flip(preg_grep($pattern, array_keys($input), $flags)));
    }
}

Jetzt nur mit Feldern arbeiten, die mit "_id" enden. Dies ist mein größtes Problem. Wenn eine Beziehung nicht NULL ist, gibt die Datenbank einen Fehler aus, da der Fremdschlüssel "" nicht gefunden werden kann.

Funktioniert perfekt. Jeglicher Kommentar?

29
Israel Ortuño

Verwenden Sie das Modellereignis "save", um nach leeren Modellen zu suchen und sie explizit auf null zu setzen. "Projekt" ist in diesem Beispiel der Name meines Modells. Setzen Sie diese Funktion in eine Hilfsfunktion und verdrahten Sie sie mit allen Ihren Modellen.

Project::saving(function($model) {
    foreach ($model->toArray() as $name => $value) {
        if (empty($value)) {
            $model->{$name} = null;
        }
    }

    return true;
});

UPDATE FÜR LARAVEL 5 (11. April 2016)

Am Ende habe ich auch eine HTTP-Middleware erstellt, um die Eingabedaten aus der http-Anfrage zu bereinigen, zusätzlich zu den Daten, bevor sie an die Datenbank gesendet werden.

class InputCleanup
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $input = $request->input();

        array_walk_recursive($input, function(&$value) {

            if (is_string($value)) {
                $value = StringHelper::trimNull($value);
            }
        });

        $request->replace($input);

        return $next($request);
    }
}
10
craigtadlock

Ich habe selbst nach der Antwort darauf gesucht, und ich kann Mutators ( http://laravel.com/docs/eloquent#accessors-and-mutators ) am nächsten finden.

Das gleiche Problem wurde durch Hinzufügen einer (magischen!) Mutator-Methode für das Fremdschlüsselfeld im Modell gelöst:

public function setHeaderImageIdAttribute($value)
{
    $this->attributes['header_image_id'] = $value ?: null;
}

Bei einem Tisch mit vielen Fremdschlüsseln kann dies etwas sperrig werden, aber es ist die "eingebaute" Methode, die ich für die Handhabung dieses Problems gefunden habe. Der Vorteil ist, dass es magisch ist. Alles, was Sie tun müssen, ist, die Methode zu erstellen, und Sie können loslegen.

60
Trip

Laravel 4

Wenn es notwendig ist, können Sie eine leere Zeichenfolge in einem Array mit filterung entfernen.

$input = array_filter(Input::all(), 'strlen');

Wenn Sie etwas wie array('a' => 'a', 'b' => '') haben, erhalten Sie: array('a' => 'a').

Soweit ich weiß, wird Laravel Eloquent ORM dieses Feld wie NULL behandeln, wenn im Feld kein Feld für die Massenzuweisung angegeben ist.


Laravel 5

$input = array_filter(Request::all(), 'strlen');

oder

// If you inject the request.
$input = array_filter($request->all(), 'strlen');
19
Rubens Mariuzzo

Wahrscheinlich mehr generische Lösung:

class EloquentBaseModel extends Eloquent {

    public static function boot()
    {
        parent::boot();

        static::saving(function($model)
        {
            if (count($model->forcedNullFields) > 0) {
                foreach ($model->toArray() as $fieldName => $fieldValue) {
                    if ( empty($fieldValue) && in_array($fieldName,$model->forcedNullFields)) {
                        $model->attributes[$fieldName] = null;
                    }
                }
            }

            return true;
        });

    }

}

Das Modell, für das Sie leere Formularfelder bereinigen müssen, sollte diese Klasse erweitern. Dann sollten Sie das Feld $ forcedNullFields mit Feldnamen füllen, die bei leeren Formularfeldern NULL sein müssen:

class SomeModel extends EloquentBaseModel {
    protected $forcedNullFields = ['BirthDate','AnotherNullableField'];
}

Und das ist alles, Sie sollten nicht denselben Code in Mutatoren wiederholen.

11

Bei einer Formulareingabe ist es normal und logischer, leere Werte anstelle von Nullwerten zu haben.

Wenn Sie wirklich denken, der beste Weg, dies zu tun, besteht darin, die Eingabe direkt in Ihre Datenbank zu übernehmen, als wäre die Lösung, leere Werte auf Null zu setzen, so etwas.

$input = Input::all();
foreach ($input as &$value) {
    if (empty($value) { $value = null; }
}
$new = new Contact(Input::all());
$new->save();

Ich persönlich bin mit diesen Lösungen nicht einverstanden, aber es funktioniert für einige Leute.

1
Nico Kaag

Eine weitere einfache Lösung besteht darin, eine Basismodellklasse zu erstellen und Modelle daraus zu erweitern:

class Model extends \Illuminate\Database\Eloquent\Model
{
    /**
     * Set field to null if empty string
     *
     * @var array
     */
    protected $forcedNullFields = [];

    /**
     * Set a given attribute on the model.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return \Illuminate\Database\Eloquent\Model
     */
    public function setAttribute($key, $value)
    {
        if (in_array($key, $this->forcedNullFields) && $value === '') {
            $value = null;
        }

        return parent::setAttribute($key, $value);
    }
}

Dann füllen Sie einfach die erforderlichen Felder in $ forcedNullFields für jedes Modell aus, falls erforderlich.

1
Vedmant