zachleigh / laravel-property-bag Goto Github PK
View Code? Open in Web Editor NEWAdd settings to any Laravel model.
License: MIT License
Add settings to any Laravel model.
License: MIT License
Is there a way to add property bags as a new model is created ?
Currently it looks like the model must be existing first
$user = new User($data);
$user->save();
//Then add settings
$user->settings(['valid_date_or_birth',false]);
There is no way to add those settings prior to saving ?
$user = new User();
$user->settings(['valid_date_or_birth',false]);
//The problem is that this will trigger a SQL query
//I am sure a workaround could be to set the settings first before adding any other data
// $user->save(); here then filling the data later on
$user->fill($data); // include operations that will be affected by the settings
$user->save();
One of the issues I have been running into is that I have settings in my model that affect some attributes and mutators. For example. If this valid_date_or_birth setting affect how a date format should change in either an accessor or a mutator. Because the user would not have an ID at the time this setting is stored, It will fail.
The problem is that as soon as the settings is set, it triggers a SQL query. However I would like to set those settings so that I can do extra computations (especially for models not currently saved)
and save those settings when its time to do so
class User extends Model{
public function getDateAttribute(){
//Perform operation based on the user settings
}
public function setDateAttribute(){
//Perform operation based on the user settings
}
}
php artisan migrate --provider="LaravelPropertyBag\ServiceProvider"
That --provider
option doesn't exist in 5.3. I assume it can be changed to php artisan migrate
?
json datatype not supported by MariaDB. Change to varchar.
hello,
this is my code :
App\Settings\UserSettings.php
protected $registeredSettings = [
'payment_method' => [
'allowed' => ['bank', 'paypal','payoneer'],
'default' => 'bank'
],
];
My controller
$user = auth()->user();
$request->validate([
'payment_method' => 'in:bank,paypal,payoneer'
]);
if($request->filled('payment_method')){
if(!$user->settings()->keyIs('payment_method', $request->payment_method)){
$user->settings(['payment_method',$request->payment_method]); //Problem is here
}
}
GET request URL : /settings/payments?payment_method=payoneer
And it works only with : paypal as a value
/settings/payments?payment_method=paypal
i have no idea whats going on
1- "paypal" works because of the condition before saving the settings
2- i forgot to mention that i'm using laravel 5.7
Hi!
Something should be wrong here ...
When I do something like this:
\App\models\User::withSetting("company", "name")
it performs this query:
select * from `property_bag` where `resource_type` = 'App\Models\User' and `property_bag`.`resource_id` in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
and also all these queries:
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 1 and `property_bag`.`resource_id` is not null and `resource_id` = 1
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 2 and `property_bag`.`resource_id` is not null and `resource_id` = 2
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 3 and `property_bag`.`resource_id` is not null and `resource_id` = 3
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 4 and `property_bag`.`resource_id` is not null and `resource_id` = 4
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 5 and `property_bag`.`resource_id` is not null and `resource_id` = 5
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 6 and `property_bag`.`resource_id` is not null and `resource_id` = 6
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 7 and `property_bag`.`resource_id` is not null and `resource_id` = 7
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 8 and `property_bag`.`resource_id` is not null and `resource_id` = 8
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 9 and `property_bag`.`resource_id` is not null and `resource_id` = 9
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 10 and `property_bag`.`resource_id` is not null and `resource_id` = 10
select * from `property_bag` where `property_bag`.`resource_type` = 'App\Models\User' and `property_bag`.`resource_id` = 11 and `property_bag`.`resource_id` is not null and `resource_id` = 11
And this is in my development environment with 11 users ... I can't imagine if I have 3000 users and it has to do 3000 queries.
I think there's a missing "join" somewhere in the "withSetting" method.
Iโm thinking about having some settings that are only available to premium users. Can we add middleware to UserSettings.php?
@zachleigh - i know about withSetting
.
It is a solid solution, but i do not think it scales very well
What would you say about this approach?
If the model's setting value is default, i do not expect to see a record in property bag.
If it is different from default, a record is in DB.
So:
/**
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $key
* @param mixed $value
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeWhereHasSetting(Builder $query, $key, $value = null): Builder
{
// if the $value matches the default,
// we need to return all models that DO NOT have the key in their property bag
// otherwise, we need to scope DB for records that have it
$default = $query->getModel()->defaultSetting($key);
// matches precisely
if ($default === $value) {
return $query->whereDoesntHave(
'propertyBag',
fn(Builder $builder) => $builder->where('key', $key)
);
}
// first we "cast" the value as array - same way Eloquent will
$value = json_encode(Arr::wrap($value));
// however, for lookup to work, we need to wrap the lookup string in double quotes
return $query->whereHas(
'propertyBag',
fn(Builder $builder) => $builder->where('key', $key)->whereRaw('`value` = ?', json_encode($value))
);
}
i'm getting this error after running php artisan migrate
full error :
Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes (SQL: alter table 'property_bag' add unique 'property_bag_resource_type_resource_id_key_unique'('resource_type', 'resource_id', 'key'))
at /vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
660| // If an exception occurs when attempting to run a query, we'll format the error
661| // message to include the bindings with SQL, which will make this exception a
662| // lot more helpful to the developer instead of just the database's errors.
663| catch (Exception $e) {
> 664| throw new QueryException(
665| $query, $this->prepareBindings($bindings), $e
666| );
667| }
668|
Exception trace:
1 Doctrine\DBAL\Driver\PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes")
/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:119
2 PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 1000 bytes")
/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117
Hello,
This is a really awesome. Thanks for sharing. I'm wondering, is it possible to retrieve all users with a particular setting through the user Model? I figure the via setting model below could also work but maybe you have a way more efficient way?
PropertyBag::where('key', 'music_notifications')->where('value', true)->pluck('owner_id');
Edit nvm. Took me a while to understand set() doesn't create if it is the default value.
Although the json_encode is ugly if we're not using json in our db
Hello,
Can your package be used for plain Non ORM Classes?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.