简体   繁体   中英

Laravel appending JSON object when filtering columns with a given value

I'm trying to create a search bar to allow users to:

(1) filter two tables with a given value,

(2) and also appending a 'status' column inside each 'row'

I did the first part like following:

public function getFilterBooks($input)
{
    $books = DB::table('books')
    ->join('categories', 'books.cat_id', '=', 'categories.id')
    ->where('b_name', 'LIKE', '%' . $input . '%')
    ->orWhere('b_author', 'LIKE', '%' . $input . '%')
    ->orWhere('cat_name', 'LIKE', '%' . $input . '%')
    ->get();
 }

return Response::json($books);

The JSON results returns fine:

[ { "id" : 1,
    "b_name" : "foo Name",
    "b_author" : "bar author",
    "cat_name" : "foobar cat",
  },
  { "id" : 2,
    "b_name" : "foo Name2",
    "b_author" : "bar author2",
    "cat_name" : "foobar cat2",
  }
 ]

However, I want to add some logical attribute here, such as when the b_author name is equal to the logged-in user fullname , then show the status as true , else false

Something like this: (Obviously it won't work)

if($books.b_author == Auth::user()->fullname){
  //set status as 'true'
}

Add should show something like this:

[ { "id" : 1,
    "b_name" : "foo Name",
    "b_author" : "bar author",
    "cat_name" : "foobar cat",
    "status" : true
  },
  { "id" : 2,
    "b_name" : "foo Name2",
    "b_author" : "bar author2",
    "cat_name" : "foobar cat2",
    "status" : false
  }
 ]

So the JSON result returns differently depending on the logged in user.

If you don't use other members' posts at all, your query is wrong. Should be like this:

$books = DB::table('books')
    ->join('categories', 'books.cat_id', '=', 'categories.id')
    ->where(function ($clause) {
        $clause->where('b_name', 'LIKE', '%' . $input . '%')
            ->orWhere('cat_name', 'LIKE', '%' . $input . '%')
    })
    ->where('b_author', Auth::id())
    ->get();

If you do use them hovewer, add this two piece of code to your model:

protected $appends = [ 'status' ];

-

public function getStatusAttribute()
{
    return $this->b_author == Auth::user()->fullname;
}

I think this can be solve through eloquent model, please have a look my solution used in a project.

For the simple of the solution I just override the toArray() method.

For elxample:

class Example extends \Eloquent {
    //...
    public function toArray(){
        $array = parent::toArray();
        $array['status'] = ($array['b_author'] == Auth::user()->fullname)?true:false; 
        //just updating to required attribute result
        return $array;
    }
}

And whenever i call this model using:

Example::all()->toArray()

which will add automatically a element to all element of array.

Update

Another way to handle logical attribute in a model:

In order to force your attribute to be returned in the array, add it as a key to the $attributes array.

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

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

Update-1

As per the 5.1.

class User extends Eloquent {
 protected $appends = array('status');

    public function getStatusAttribute() {
      return 'someStatus';
   }
}

If you still face something confusing to resolve it let me know.

I suppose the easiest way would be to do it in the database and add a select clause, something like this:

public function getFilterBooks($input)
{
    $books = DB::table('books')
    ->join('categories', 'books.cat_id', '=', 'categories.id')
    ->select(
        ['*', DB::raw('books.b_author = :username as status')], 
        [Auth::user()->fullname]
    )
    ->where('b_name', 'LIKE', '%' . $input . '%')
    ->orWhere('b_author', 'LIKE', '%' . $input . '%')
    ->orWhere('cat_name', 'LIKE', '%' . $input . '%')
    ->get();
}

return Response::json($books);

The reason for putting the Auth::user()->fullname in a separate array is because we want to escape it properly even though it's used in a DB::raw() query. And since you want all of the regular columns, we add the '*' to the select array as well.

Edit: explanation as requested:

When we do select x = y as z ... in SQL, we compare x with y, and z is set to 1 if they're equal, or 0 if they're not.

So in books.b_author = :username as status , we're saying "compare the b_author column from the table books with the value :username". But :username is just a placeholder for a value we'll insert later. That's what we do in the second array, [Auth::user()->fullname] - we replace :username with the logged-in user's fullname value.

That way, you can make the comparison directly in the query without any hassle in php afterwards to manipulate the results array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM