mattcrowe
mattcrowe

Reputation: 424

Laravel Eloquent Model Attributes

After instantiating a model class that extends Laravel's Eloquent Model class, is there a way to determine if the property/attribute maps to the table, and therefore can be saved to the table?

For example, I have a table announcements with columns id, text and "created_by".

How can I know created_by is an attribute and will be saved if set?

$announcement = new Announcement();

isset($announcement->created_by) understandably returns false if I haven't explicitly set the value yet. I have tried various functions inherited from the Eloquent model class, but so far none have worked. I'm looking for something like:

$announcement->doesThisMapToMyTable('created_by') that returns true whether or not $announcement->created_by has been set.

Upvotes: 22

Views: 77137

Answers (6)

GeeC
GeeC

Reputation: 378

I realise this is very old but there is an even simpler answer that doesn't require querying the columns of the table on which the model is based.

If you are using standard timestamp columns in the models where you use them, you can use the following to determine if the 'created_at' column exists:

$model->usesTimestamps();

If you are using a non-standard name for the created column, you would need to additionally get the name of that column using:

$model->getCreatedAtColumn();

Upvotes: 0

Leith
Leith

Reputation: 3299

Rather than writing your own lookup into the database internals, you can just use the Schema facade to look up the columns:

use Illuminate\Support\Facades\Schema;

$announcement = new Announcement();
$column_names = Schema::getColumnListing($announcement->getTable());
if (in_array('created_by', $column_names)) {
  // whatever you need
}

Alternatively, as early as Laravel 4 there's the hasColumn() check:

use Illuminate\Support\Facades\Schema;

$announcement = new Announcement();
if (Schema::hasColumn($announcement->getTable(), 'created_by')) {
  // whatever you need
}

Upvotes: 14

Janne
Janne

Reputation: 1151

Laravel 5.4

I used Leiths answer to create generic helper method, which automatically maps JS-object to Laravel model (and basically ignores those properties which are not part of model, thus avoiding QueryBuilder error messages for undefined columns). Additionally contains simple createOrEdit -approach (even though doesn't have "does ID exist?" -validation):

    public function store(Request $request) {
        if($request->input("club")) {
            $club = \App\Club::find($request->input("club")["id"]);
        } else {
            $club = new \App\Club;
        }
        $club = self::mapModel($request->input("club"), $club);
        $club->save();
    }
    
    public function mapModel($input,$model) {
        $columns = Schema::getColumnListing($model->getTable());
        foreach ($columns as $i => $key) {
            if($input[$key]) {
                $model->{$key} = $input[$key];
            }
        }
        return $model;
    }

Upvotes: 0

mindsupport
mindsupport

Reputation: 488

For Laravel 5.4:

$hasCreatedAt = \Schema::hasColumn(app(Model::class)->getTable(), 'created_at');

    if($hasCreatedAt == true) {
       ...
    }

Upvotes: 7

Antonio Carlos Ribeiro
Antonio Carlos Ribeiro

Reputation: 87789

If your model is filled with data, you can:

$announcement = Announcement::find(1);

$attributes = $announcement->getAttributes();

isset($attributes['created_by']);

For empty models (new Models), unfortunately you will have to get the columns using a small hack. Add this method to your BaseModel:

<?php

class BaseModel extends Eloquent {

    public function getAllColumnsNames()
    {
        switch (DB::connection()->getConfig('driver')) {
            case 'pgsql':
                $query = "SELECT column_name FROM information_schema.columns WHERE table_name = '".$this->getTable()."'";
                $column_name = 'column_name';
                $reverse = true;
                break;

            case 'mysql':
                $query = 'SHOW COLUMNS FROM '.$this->getTable();
                $column_name = 'Field';
                $reverse = false;
                break;

            case 'sqlsrv':
                $parts = explode('.', $this->getTable());
                $num = (count($parts) - 1);
                $table = $parts[$num];
                $query = "SELECT column_name FROM ".DB::connection()->getConfig('database').".INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'".$table."'";
                $column_name = 'column_name';
                $reverse = false;
                break;

            default: 
                $error = 'Database driver not supported: '.DB::connection()->getConfig('driver');
                throw new Exception($error);
                break;
        }

        $columns = array();

        foreach(DB::select($query) as $column)
        {
            $columns[$column->$column_name] = $column->$column_name; // setting the column name as key too
        }

        if($reverse)
        {
            $columns = array_reverse($columns);
        }

        return $columns;
    }

}

Extend your model from it:

class Announcement extends BaseModel {

}

Then you will be able to:

$columns = $announcement->getAllColumnsNames();

isset($columns['created_by']);

Upvotes: 37

morawcik
morawcik

Reputation: 90

I used to !empty($announcement->created_by) and it's work great for my

Upvotes: -2

Related Questions