Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json columns can be set using object syntax but not retrieved #37767

Closed
coleshirley opened this issue Jun 21, 2021 · 6 comments
Closed

Json columns can be set using object syntax but not retrieved #37767

coleshirley opened this issue Jun 21, 2021 · 6 comments

Comments

@coleshirley
Copy link
Contributor

  • Laravel Version: 8.47.0
  • PHP Version: 8.0.5
  • Database Driver & Version: mysql 8.0

Description:

If you have an eloquent model that utilizes json columns it is possible to use object property syntax to set a value within the json column but you are unable to retrieve and values from the json column using the same syntax.

For example (assuming I have a Post model defined with a "properties" json column):

image

This ability to set a json attribute using object syntax is found in laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php setAttribute($key, $value) lines 778 - 780 where a check is done to see if $key contains '->'.

The equivalent code for getAttribute($key) in the same file does not exist

Steps To Reproduce:

Base Laravel Install +

app/Models/Post.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
}

database/migrations/2021_06_21_192942_create_posts_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->json('properties')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
@driesvints
Copy link
Member

Hi there,

Thanks for reporting but it looks like this is a question which can be asked on a support channel. Please only use this issue tracker for reporting bugs with the library itself. If you have a question on how to use functionality provided by this repo you can try one of the following channels:

However, this issue will not be locked and everyone is still free to discuss solutions to your problem!

Thanks.

@coleshirley
Copy link
Contributor Author

@driesvints Maybe I didn't explain it the right way but this issue is related to missing functionality in the framework not a support request.

If you look at my tinker output that I included an image of I demonstrated that

$model->{'properties->title'} = 'My Title';

works just the way you would expect and sets the title key in the $properties json attribute.

However running

echo $model->{'properties->title'};

returns null when it would be expected that it would return 'My Title'

I don't see how this is a support request

@driesvints
Copy link
Member

It was removed due to it being a security breach. Please ask on a support channel or look around for relevant articles.

@coleshirley
Copy link
Contributor Author

For anyone interested in this functionality it can be added to an eloquent model class with the following code:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class Post extends Model
{
    /**
     * Get an attribute from the model.
     *
     * @param  string  $key
     * @return mixed
     */
    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);

        if (is_null($value) && Str::contains($key, '->')) {
            $value = $this->getJsonAttribute($key);
        }

        return $value;
    }

    /**
     * Get a given JSON attribute on the model.
     *
     * @param  string  $key
     * @return $this
     */
    public function getJsonAttribute($key)
    {
        [$key, $path] = explode('->', $key, 2);

        return Arr::get($this->getArrayAttributeByKey(
            $key
        ), str_replace('->', '.', $path));
    }
}

@browner12
Copy link
Contributor

anyone have any idea where it was removed? i've been digging and cannot find it. would love to read more about it, and see if 3 years later we can do this without the security issue.

@browner12
Copy link
Contributor

I think I finally found some related stuff:

#33777
#34640
#37726

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants