Giter Site home page Giter Site logo

laravel-metable's People

Contributors

aneesdev avatar anilkumarthakur60 avatar braunson avatar frasmage avatar geosot avatar leocolomb avatar luukvdo avatar saulens22 avatar squatto avatar tormjens avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-metable's Issues

Possible issue?

Hi, I don't really know if it's a bug ...

I have a table with a million records and the "meta" table has more or less the same. The problem is that the "whereHasMeta" method is extremely slow. Is it a problem with the library that does not manage so many records well?

Screenshot_481
Thank you.

Usage without full Laravel Package

Hey,

is the possibility of using this package without pulling in the full laravel package an option for you?

It would be nice to be able to use the package when only using the illuminate/database because you just need eloquent. It currently fails trying to get the config() since there is no service provider loaded when outside of the laravel scope.

Or is there any workaround for this?

Would be nice to hear from you.

Marcus

Adding a column to the meta table for filtering

I added a column team_id to the meta table, which I'm filling using an observer. That works fine.

But how can you add a global scope to add a filter on team_id on each getMeta() and getAllMetas() request, without changing the package code?

Error on whereMetaIn method

Hey,

there is a lack of use ($key) in src/Metable.php on line 265, so because of it whereMetaIn fails. Would be great if some of the contributors will fix it.

And of course, thanks for so good package!

Regards,
Giorgi

Deleteing Meta that does not exist

I have a "Settings" form that will be used to update Meta details about a model.

If a field is left blank, rather than store a NULL value I would prefer to unset the Meta using $model->removeMeta($key) so that later I can use the default value option.

It would be great if I could do $model->removeMeta($key) on a model where the meta has not been set yet, without it throwing an error: Call to a member function delete() on null from line 138 of Metable: $this->getMetaCollection()->pull($key)->delete();

I know I can first check if the Meta exists, but that adds a lot of extra database calls when looping over a long form.

an issue that came up when using multiple databases

I use multiple databases and I ran into an issue where it was looking for my meta table on the wrong database. I've had this happen to me before as I often use multiple databases in my projects, and the easy fix is usually to just prefix the database name (not the connection name, but the actual database name) in front of the table.

So in my Meta model

<?php

namespace MyApp\Api\Models\Data;

use Plank\Metable\Meta;

class ProfileMeta extends Meta
{
    protected $connection = 'data';

    protected $table = 'api_data.profile_meta';

    public function __construct(array $attributes = [])
    {
        $this->setConnection('data');

        parent::__construct($attributes);
    }
}

I appended api_data. in front of profile_meta.

I've done this countless times for models and it usually fixes my JOINS that way. In this case it also worked and it fixed all my JOIN issues between two models on two different databases.

However, surprisingly it completely broke laravel-metable and I could not longer setMeta

When trying to setMeta it would always result in my value / key being lost and being set to null.

I was very puzzled by this was this happening.

After some debugging I narrowed it down to the makeMeta method inside the Metable trait.

Specifically due to the way you create the model, by passing the attributes to the constructor, when you've appended the database name in front of the table the setValueAttribute method does not get called ??

I have no idea why.

But I found a fix that works.. I am overriding the makeMeta method on my model that uses Metable and I changed it

from

    protected function makeMeta(string $key = '', $value = ''): Meta
    {
        $className = $this->getMetaClassName();

        $meta = new $className([
            'key' => $key,
            'value' => $value,
        ]);
        $meta->metable_type = $this->getMorphClass();
        $meta->metable_id = $this->getKey();

        return $meta;
    }

to

    protected function makeMeta(string $key = '', $value = ''): Meta
    {
        $className = $this->getMetaClassName();

        $meta = new $className();
        $meta->key = $key;
        $meta->value = $value;

        $meta->metable_type = $this->getMorphClass();
        $meta->metable_id = $this->getKey();

        return $meta;
    }

And then setValueAttribute gets called and my joins work and everything works.

I don't know if you understand why this is happening? Or if you would mind modifying your makeMeta to the way I set it up?

Would love to know more.

Many thanks!

Feature Request - default values for unset meta values

At least in my usecase, I use this tool to store attributes which only apply to a few users (otherwise, I'd just add it to the main table). I use this for an intranet app to store when users are out of office - it only ever applies to a small subset of users, and after it is set back, there's no reason to continue to store the value.

Many times, I find myself writing code like this:

          // default = true
          if(is_null($artist->artistactive)) {
            $out['active'] = true;
          } else {
            $out['active'] = $artist->artistactive;
          }

I'd love a way to specify default values in the model. This would be implemented in two parts:

  1. If the attribute is not found, but the given attribute is in the default value list, the default value is returned transparently.
  2. If the attribute is set to the value which is equal to the default value, the value is deleted from the table (activating case 1 for this entry)

This would reduce the code down to:

         $out['active'] = $artist->artistactive;

This would also help catch more logical errors and be more DRY, as if an implied default state ever changes, it would involve changing all these checks.

Just a thought, I might even submit a PR myself if I have time.

at a loss as to why whereMetaIn is not working on simple array

I've been really scratching my head for well over an hour trying to figure this one out.. so I figured it might be best to ask because I'm at a loss.

I have a meta key that holds simple arrays of 1 to 4 strings.

Screen Shot 2022-02-13 at 3 52 42 AM

Then I've isolated my query entirely, only applying a single condition. I want to count the number of models that have friendship within their array... which is thousands of them

        $interests = ['friendship'];
        $profiles = Profile::whereMetaIn('interested_in', $interests)->get();
        dd($profiles->count());

This returns 0 every time ?? What am I doing wrong? Must be brain farting heavily here...

Ideally I want to return models that contain either friendship or relationship, you get the idea.. one or the other but not necessarily both.

Would appreciate a hint! This looks dead simple yet somehow..

Thanks!

error: Call to a member function has() on null

we have Serious problem in our project , it's related to your package what can we do ?

    public function hasMeta(string $key): bool
    {
        return $this->getMetaCollection()->has($key);
    }

error:

Call to a member function has() on null

Previous versions returned meta items key as key field

So let me describe this a bit more, as the title says. In previous versions when I returned the collection of a meta collection, it would be as the following:

` "meta" => Illuminate\Database\Eloquent\Collection {#2723 ▼
#items: array:5[▼

    "source" => Plank\Metable\Meta {#2989 ▶}
    "chamberofcommerce" => Plank\Metable\Meta {#2990 ▶}
    "sbi" => Plank\Metable\Meta {#3551 ▶}
    "telephone" => Plank\Metable\Meta {#3552 ▶}
    "website" => Plank\Metable\Meta {#2727 ▶}

]`

As you can see, the keys are strings which relate to the Meta field 'key'. Now as of version 4.0 (previously 1.1), it is returned as:

` "meta" => Illuminate\Database\Eloquent\Collection {#761 ▼
#items: array:28 [▼

    0 => Plank\Metable\Meta {#764 ▶}
    1 => Plank\Metable\Meta {#765 ▶}
    2 => Plank\Metable\Meta {#766 ▶}
    3 => Plank\Metable\Meta {#767 ▶}
    4 => Plank\Metable\Meta {#768 ▶}

]`

The meta collection is eager loaded through the model;

protected $with = ['meta'];

Any solution for this problem without major changes to the code, in our current project we have alot of links to the key of items in the meta collection.

BLOB/TEXT column 'value' can't have a default value

I am running mariadb 10.0.19 but according to the MySQL docs https://dev.mysql.com/doc/refman/5.7/en/blob.html a BLOB/TEXT column is not allowed to have a default value.

[Illuminate\Database\QueryException]                                                                                                                                                                                             
SQLSTATE[42000]: Syntax error or access violation: 1101 BLOB/TEXT column 'value' can't have a default value (SQL: create table `meta` (`id` int unsigned not null auto_increment primary key, `metable_type` varchar(255) not null, `metable_id` int unsigned not null, `type` varchar(255) not null default 'null', `key` varchar(255) not null, `value` longtext not null default '') default character set utf8 collate utf8_unicode_ci)  
[PDOException]                                                                                               
SQLSTATE[42000]: Syntax error or access violation: 1101 BLOB/TEXT column 'value' can't have a default value

What are the impacts of removing the default on the rest of the code? I propose removing it, while some platforms throw a warning others throw an error. As of this writing the mode mysql is running at determines if an error will be thrown (STRICT MODE throws an error).

Artisan command to purge duplicates

I'm writing an artisan command that will identify duplicates (metable_type + metable_id + key) and delete all but the most recent one (the highest id).

I have a few to deal with. This is only 10 of the 33 keys with duplicates... 😳

image

Do you want me to send you the command when I'm done? I'm thinking it may be useful to those that are upgrading to version 5, considering that they'll be deleting them by hand otherwise.

Enforce DataTypes in Meta values

Hello and many, many thanks for this Package (especially the DataTypesHandlers approach)

I would like to make a question:
You already provide the mechanism for default meta values per key, however is there any suggestion or mechanism, in case we want to enforce/validate the proper type/Handler for each Meta key inside Metable Models?

I am working in a project and this need came out, as we want to enforce specific types for some metas (ideally through configuration)

is it possible to query json stored inside meta rows?

Previously I was doing something like this


            $this->where('matching_preferences->age->min', '<=', $profile->getMeta('age', null));
            $this->where('matching_preferences->age->max', '>=', $profile->getMeta('age', null));

But now that I've moved matching_preferences.age to a meta field. I don't know how to perform my lookup anymore.

I tried the below but that doesn't work.

            $this->whereMeta('matching_preferences.age->min', '<=', $profile->getMeta('age', null));

A sample content of matching_preferences.age is

{"min":22,"max":44}

I guess I could create two meta rows, one for matching_preferences.age.min and one for matching_preferences.age.max but if it's possible to query json inside meta records I would prefer to do that.

Any help would be greatly appreciated! Thank you!

Using Metadata for Table Relationships in Laravel

Is it possible to utilize meta for a relationship with another table? For example, I have a "products" table and metadata where the "key" is "mistake" and the value is "1". So, if I want to retrieve the meta "mistake", then based on the key with "1", I want to retrieve data from the "mistakes" table where mistakes.id=1. Something similar to what Laravel has for hasOne()... Thank you.

joinMetaTable function in Metable trait should use getMorphClass override

Greetings,

Thank you for your efforts on this plugin, particularly with the documentation and the 0 issues count :)

I've just discovered an issue with some single table inheritance functionality I am putting together. I am overriding the getMorphClass function in my Category model. This model has the Metable trait on it.

This getMorphClass override works everywhere except for functions that use the joinMetaTable function on line 379.

    private function joinMetaTable(Builder $q, string $key, $type = 'left'): string
    {
       ...
        // Join the meta table to the query
       ...
                ->where($alias . '.' . $relation->getMorphType(), '=', get_class($this));  // < 379

this should ideally read

    private function joinMetaTable(Builder $q, string $key, $type = 'left'): string
    {
       ...
        // Join the meta table to the query
       ...
                ->where($alias . '.' . $relation->getMorphType(), '=', $this->getMorphClass());

This resolves the issue with that getMorphClass function being customised (including with morphMaps etc).

Right way for meta type?

So i have a html checkbox with the value of true like this:

<input name="is_activated" type="checkbox" value="true"">

then use syncMeta method and the type column saved as string, it also applied with the setMeta method unless i have to cast it as boolean as:

foreach ($request->meta as $key => $value) {
  if ($key == 'is_activated') {
      $post->setMeta($key, (bool) $value);
  }
}

So, is there a better way of doing this?

Setting keys for Collection in setRelation() throws errors

When we are dispatching a job to the queue, and the job class contains a Model that uses the Metable trait, it will throw the following error:

Error: Cannot unpack array with string keys in /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Collection.php:605

As the error makes clear, this is possible:

$relations = [
    0 => ['value'], 
    1 => ['value']
];
array_intersect(...$relations)

But this is not:

$relations = [
    'key' => ['value'], 
    'another_key' => ['value'
]];
array_intersect(...$relations)

And this is happening due to the override of setRelation():

    /**
     * {@inheritdoc}
     */
    public function setRelation($relation, $value)
    {
        if ($relation == 'meta') {
            // keep the meta relation indexed by key.
            /** @var Collection $value */
            $value = $value->keyBy('key');
        }

        return parent::setRelation($relation, $value);
    }

Removing the keyBy() index fixes it.

Call to undefined method Plank\Metable\Meta::getAttributesForInsert()

Hello,

I have issues with insert array meta - setManyMeta().

I have:

$inorder->setManyMeta([
            'inorder_price' => $request->price,
            'customer_order' => $request->customer_order,
        ]);

and alert is:

BadMethodCallException
Call to undefined method Plank\Metable\Meta::getAttributesForInsert() 

obrázok

Please, help me :)

Deadlock found when trying to get lock

Hi,

I know this could a another problem; but i think it is related to the recordcount in meta since we have 5.121.049 records in that table. The message from MySQL:

Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction (SQL: insert into my-table-meta (key, metable_id, metable_type, type, value) values (somekey, 181308, App\Models\Model, string, 2022-01-29 07:05:55),
on duplicate key update type = values(type), value = values(value)) at file /home/myproject/vendor/laravel/framework/src/Illuminate/Database/Connection.php at line 712

Any thoughts on this?

Error: setManyMeta

Hi, without further a do, please see use-case below:

Versions

  • Laravel 8+
  • plank/laravel-metable "^5.0"
  • nunomaduro/collision "^5.0"
  • spatie/laravel-web-tinker "^1.7"

Example

$model->setManyMeta($metas = [
    'title' => 'Pen-Pineapple-Apple-Pen',
    'keywords' => [
        'Pen-Pineapple-Apple-Pen', 
        'Pen-Pineapple',
        'Pineapple-Apple',
        'Apple-Pen',
        'Pineapple',
        'Pen',
        'Apple',
    ],
]);

Error (Collision)

  ErrorException

  Array to string conversion

  at vendor/laravel/framework/src/Illuminate/Support/Str.php:560
    556557$result = array_shift($segments);
    558559foreach ($segments as $segment) {
  ➜ 560$result .= (array_shift($replace) ?? $search).$segment;
    561▕         }
    562563return $result;
    564▕     }
    

Error (Web-Tinker)

PHP Warning: Array to string conversion in
/home/dev/www/cleanmypco/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 603

Temporary Solution (foreach)

foreach ($metas as $key => $value) {
    $model->setMeta($key, $value);
}

Cheers! Please fix.

can you please add a mechanism for ignoring your migration

I followed your advice on how to rename the table and tried it out. I grabbed your migration file and copied it to my migration folder and kept the exact same name. However that did not result in my migration superseding yours because of the way I arrange my migration files in a separate subfolder.

It would be very useful then if you could add a mechanism which has become popular in many other packages such as https://laravel.com/docs/8.x/telescope#migration-customization

Either that or simply a new configuration option.

Alternatively, if you could allow us to specify both the table name, and database connection, in the config file that would also do the trick. Although I do prefer having full control over the migration as I may decide to add some columns or add an index that you aren't using.

Many thanks

Class App\Meta not found error

I am testing this package in tinker. This is what I did to set a meta for user model

$user = User::first();
$user->setMeta('city','Dhaka');

PHP Error: Class 'App/Meta' not found in D:/drivi-blade/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php on line 656

This is top of my user model

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Plank\Metable\Metable;

class User extends Authenticatable
{
    use Notifiable;
    use Metable;

Get all meta keys/values for ALL

Hi there,
I am trying to get all the keys and values used across my products that use Metable.
I'm trying to use this for a search/filter.

What I would like would be

-Key 1
-- Value 1
-- Value 2
-Key 2
-- Value 3
-- etc

Is this even possible?

$all_meta = Meta::where('metable_type', Product::class)
    ->where('key', 'LIKE', $format . '_%')
    ->get()
    ->unique(function ($item) {
        return $item['key'].$item['value'];
    })
    ->each(function ($item, $key) {
        return $item->pluck('value','key');
    });

This is what I have currently but I am getting the following error:

Type error: Argument 1 passed to Plank\Metable\DataType\Registry::getHandlerForType() 
must be of the type string, null given, called in 
/home/vagrant/code/store/vendor/plank/laravel-metable/src/Meta.php on line 69

I figure I am doing something dumb but can't seem to seem to see it...

TIA!

[Suggestion] `or` query methods

Would it be helpful (and would you consider merging) if I added or methods for each of the query methods? orWhereMeta(), orWhereHasMeta(), and so on. They would be helpful to avoid having to do fun things like this:

->where(fn ($query) => $query->whereMeta('hidden_from_admin', false)
                             ->orWhere(fn ($query) => $query->whereDoesntHaveMeta('hidden_from_admin'))
)

AKA "where the hidden_from_admin meta is false or it doesn't exist"

This instead could be:

->where(fn ($query) => $query->whereMeta('hidden_from_admin', false)
                             ->orWhereDoesntHaveMeta('hidden_from_admin')
)

Or this:

->where(fn ($query) => $query->whereMeta('source_order_id', $searchValue)
                             ->orWhere(fn ($query) => $query->whereMeta('source_order_number', $searchValue))
)

AKA "where the source_order_id or source_order_number meta is $searchValue"

This instead could be:

->where(fn ($query) => $query->whereMeta('source_order_id', $searchValue)
                             ->orWhereMeta('source_order_number', $searchValue)
)

The or methods will essentially just be orWhere() wrappers around the base query methods (like I'm doing above).

Let me know what you think. Thanks!

Illuminate\Database\QueryException error on php artisan:migrate

When I run the migrations, I get this error:
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes (SQL: alter table meta add unique meta_metable_type_metable_id_key_unique(metable_type, metable_id, key))

I have the latest laravel version and my wamp server is set-up as follow:
image

[BUG] All meta entries are deleted when a model is soft-deleted

It's surprising to discover this on my database but after soft deleting a row, all the meta associated with it got deleted.

After checking the code, I found the issue is here:

public static function bootMetable()
{
// delete all attached meta on deletion
static::deleted(function (self $model) {
$model->purgeMeta();
});
}

As a suggestion, I suggest changing it to

public static function bootMetable()
{
    // delete all attached meta on deletion
    static::deleted(function (self $model) {
        if (!method_exists($model, 'forceDelete') || $model->isForceDeleting()) {
            $model->purgeMeta();
        }
    });
}

Hope to see this fixed soon.

Error when trying to get all meta for object

I get an error when trying to fetch all meta belonging to an object:

Plank\Metable\DataType\Registry::getHandlerForType(): Argument #1 ($type) must be of type string, null given, called in /var/www/html/vendor/plank/laravel-metable/src/Meta.php on line 76

I have the full error stack here: https://flareapp.io/share/oPRq3OAm#F63

Running:

php: 8.1.11
laravel: 9.37.0
metable: 5.3.0

Filtering

Hi I am using your package for a sort of webshop with a couple of products. The products have multiple meta values. Is there a easy way to create some sort of product meta filtering?
Something like this:

Width:

  • 10mm (4 products)
  • 20mm (1 product)

Height:

  • 100mm (4 products)
  • 200mm (1 products)

[Question / Sugestion] Is it possible to append/query to an Array DataType?

Example:

A doctor can have none or many specialties:

  • general practitioner
  • orthopedist
  • pediatrician
  • obstetrician
$doctor1->setMeta('specialities', 'general practitioner')
$doctor1->appendToMeta('specialities','obstetrician') // How to append ?

$doctor2->setMeta('specialities', 'pediatrician')
$doctor2->appendToMeta('specialities','obstetrician') // How to append ?

How to query for all 'obstetrician' if the meta key 'specialities' is an Array converted to a json in the database ?

Cannot install this package due to phpoption version

Hi,

First of all thanks for the great package with great documentation. you guys did a great job 😄 ❤️.

I'm trying to install this package on my Laravel 9 project but I'm getting this error by the composer:

image

I'm using Laravel 9.24.0 & PHP 8.1.8. and I'm using the latest composer 2.

Seems like vlucas/phpdotenv (used by Laravel) which uses graham-campbell/result-type and this uses "phpoption/phpoption": "^1.9". but this package uses "phpoption/phpoption": "1.8.1"

Not compatible with laravel 6

I am trying to require it with composer command

composer require plank/laravel-metable

But, an error is shown like below

Your requirements could not be resolved to an installable set of packages.

Problem 1
- Installation request for plank/laravel-metable ^1.1 -> satisfiable by plank/laravel-metable[1.1.0].
- Conclusion: remove laravel/framework v6.0.1
- Conclusion: don't install laravel/framework v6.0.1

How to use it in laravel 6 ?

Performance question

Hi Guys, I just want to ask, if it's good practise to have just one and only table to storage all metas for every model. For example if I will have 80 000 users and 80 000 products and every single user / post will have at least 5 meta stored in the "meta" table then this table will have more then 800 000 rows and I am not sure how fast will be getting required data for the specific user or post.

Also, please could you give me advice, how can I change the name of the table? E.g. change the table name from "meta" to "users_meta" and I do not want to update anything inside the vendor folder

Thank you for your help.

orderByMetaNumeric throws QueryException

Hi,

I'm having an issue with ordering results based on a meta key.

The code:

public function candidates() 
{ 
        // user filters
        $filters = request('filters', []);

        // user ordering
        $orderBy = request('orderby', 'updated');
        $order = request('order', 'desc');

        // candidates per page
        $paginate = request('paginate', 100);

        // lazy load relations
        $candidate = Candidate::with(
            'aircraft_types', 
            'nationalities', 
            'instructor_qualifications', 
            'instructor_aircraft_types', 
            'licenses', 
            'positions',
            'meta'
        );

        // apply filters
        if($filters) {
            $candidate = (new CandidateFilter($filters, $candidate))->build(); // pass through a filter
        }

        if($orderBy === 'rating') {
            $candidate = $candidate->orderByMetaNumeric($orderBy, $order, true);
        } else {
            $candidate = $candidate->orderBy($orderBy, $order);
        }

	return $candidate->paginate($paginate);
}

The exception I get:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'App\Candidate' in 'on clause' (SQL: select count(*) as aggregate from `candidates` inner join `meta` as `meta__rating` on `candidates`.`id` = `meta__rating`.`metable_id` and `meta__rating`.`metable_type` = `App\Candidate` and `meta__rating`.`key` = `rating`)

Any thoughts on what might be wrong?

[Suggestion] Add created/updated timestamps

Is there any particular reason that the meta model doesn't have created/updated timestamps? They would be useful to have available at times.

I can certainly add them to my own model, of course. I'm just curious what your thoughts are about adding them to the core package.

Thanks!

[Feature Request] Queriying collections

Firstly thanks for this great package! It saves time and helps keep things clean.

I've tried to query collection but always get an empty result.
Or am I do something wrong?

Collection saved in DB:

{"class":"Illuminate\\Database\\Eloquent\\Collection","items":
  [
    {"class":"App\\Models\\Currency","key":"TRY"},
    {"class":"App\\Models\\Currency","key":"USD"},
    {"class":"App\\Models\\Currency","key":"EUR"},
    {"class":"App\\Models\\Currency","key":"GBP"}
  ]
}

Queries I've tried:

User::whereMeta('currencies', 'USD')->get();
User::whereMetaIn('currencies', ['USD'])->get();

Any chance to make such queries work?

How to filter based on multiple meta values

Rn I am using another packaged and I think I will switch it due to lack of updates. But before this, I have a question. How to query based on multiple meta values?
Let me give an example. Let's say we have some orders with 3 meta values. name, phone and email. How to get the orders which, simultaneously, contains 'a' in name, '1' in phone and 'b' in email?

[Suggestion] Merge metas with $defaultMetaValues

Currently having a Model with $defaultMetaValues with no meta, $model->getAllMeta() returns an empty collection. Wouldn't it be great to merge those $defaultMetaValues with collection when using $model->getAllMeta()?

I needed to be able to set an order for my metas

I'm using metable to power a form builder of sorts where users can build custom forms by creating various fields and then placing / re-arranging them via a UI

In order for the fields to be ordered properly I added two new fields to the meta table and am now overriding two methods from the Metable class in order to make it work

These fields are optional of course but I'm not sure you would consider this as a useful PR so I thought I would ask first and share the code here in case someone else has a similar problem.

Also if you think I could have achieved this in another way I'd love to hear your feedback

            $table->smallInteger('order')->default(0);
            $table->string('category')->nullable();
    /**
     * Relationship to the `Meta` model.
     *
     * @return MorphMany
     */
    public function meta(): MorphMany
    {
        return $this->morphMany($this->getMetaClassName(), 'metable')
        ->orderBy('category')
        ->orderBy('order');
    }

    /**
     * Add or update the value of the `Meta` at a given key.
     *
     * @param string $key
     * @param mixed $value
     */
    public function setMeta(string $key, $value, $order = 0, $category = null): void
    {
        if ($this->hasMeta($key)) {
            $meta = $this->getMetaRecord($key);
            $meta->setAttribute('value', $value);
            $meta->order = $order;
            $meta->category = $category;
            $meta->save();
        } else {
            $meta = $this->makeMeta($key, $value);
            $meta->order = $order;
            $meta->category = $category;
            $this->meta()->save($meta);
            $this->meta[] = $meta;
            $this->indexedMetaCollection[$key] = $meta;
        }
    }

[FEATURE REQUEST] Map as strict meta field keys

Hi, I would like to ask if you have a trait or maybe you want to integrate this as the package feature. As the title states, pseudo below:

class User extends Model 
{
    use Metable;

    /**
     * Specific inputs, and save as meta.
     * or... if method exists: `protected function metaFields(): array`
     * 
     * If a Meta field is not on a listed, should be left alone.
     * 
     * @var array
     */
    protected array $meta_fields = [
       'firstname',
       'lastname',
       'age',
       'sex',
       'address',
    ];
}

User::create([
    'email' => '[email protected]',
    'firstname' => 'Joe',
    'lastname' => 'Foo',
    'address' => ['street' => '...', 'city' => ..., ...]
]);

App\Models\User {
    attributes: [
        ...
        'email' => '[email protected]',
    ],
    ...
};

Retrieval:

$user->address; 
// array() [ 'street' => '...', ... ]

$user->lastname;
// Foo

Saving:

$user->email = '[email protected]';
$user->lastname = 'Bar';
$user->firstname = 'Foo';

// bulk meta save as: `setManyMeta`, which is called when `saving/updating` or `saved` model event is triggered 
// (not sure what's best), I am sure DB::transaction still captures in case.

$user->save();

$user->toArray() => [
    'id' => ...
    'email' => '[email protected]',
    'meta' => [
        'firstname' => 'Foo',
        'lastname' => 'Bar',
    ],
];

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.