Calculate 2 columns together in Yii2 model::find() function - database

I have the following working find() function in Yii2:
User::find()->select('id, name')->where(['status' => '10'])->all()
However, the User model also has the following attributes:
'credit'
'ammount'
I need to check if the 'ammount' minus 'credit' is more that a value ($price) I am passing to the function.
How can I make a User:find() query where I am only getting the user objects where the amount minus credit is larger than the value I am checking against?
Thanks

I assume the amount and credit are in the user table so you can do something like.
User::find()->select([new \yii\db\Expression('id,amount,credit')])
->where(['status' => '10'])
->andWhere('amount - credit > :yourAmount',[':yourAmount'=>$price])
->all();
or use addParams() to bind the custom value
User::find()->select([new \yii\db\Expression('id,amount,credit')])
->where(['status' => '10'])
->andWhere('amount - credit > :yourAmount')
->addParams([':yourAmount'=>$price])
->all();

Related

Extracting an array of values from an array of hashes in Puppet

I have the following array of hashes in hiera:
corporate_roles:
- name: 'user.1'
system_administrator: true
global_administrator: false
password: TestPassword1234
- name: 'user.2'
system_administrator: true
global_administrator: true
password: TestPassword1234
I need to extract a list of users with a give role (eg global_administrator) to be assigned later on.
I managed to use the map function to extract the data I need:
$corporate_roles = lookup('corporate_roles')
$global_admins = $corporate_roles.map | $hash | { if ($hash['global']){$hash['name']}}
notify { "global admins are: ${global_admins}":
}
However this results in undef values seemingly making their way into the array for the users that don't match the criteria:
Notice: /Stage[main]/salesraft_test/Notify[global admins are: [, user.2]]/message: defined 'message' as 'global admins are: [, user.2]'
Notice: Applied catalog in 0.04 seconds
I can get around this by using the filter function as such:
$test = $global_admins.filter | $users | {$users =~ NotUndef}
Which results in clean output:
Notice: /Stage[main]/salesraft_test/Notify[global admins are: [user.2]]/message: defined 'message' as 'global admins are: [user.2]'
Notice: Applied catalog in 0.03 seconds
But I suspect there must be a better way of doing this and I am either missing some logic in my map or I am likely using the wrong function altogether for this.
I would like to know if there is a better way to achieve what I am trying to do?
But I suspect there must be a better way of doing this and I am either
missing some logic in my map or I am likely using the wrong function
altogether for this.
map() emits exactly one output item for each input item, so if your objective is to apply a single function to obtain your wanted output from your (lengthier) input, then indeed, map will not achieve that.
I would like to know if there is a better way to achieve what I am trying to do?
Personally, I would do the job by filtering out the hashes you want from your input and then mapping those to the wanted output form (as opposed to mapping and then filtering the result):
$global_admins = $corporate_roles.filter |$hash| {
$hash['global_administrator']
}.map |$hash| { $hash['name'] }
I like that because it's nice and clear, but if you want to do it with one function call instead of two then you're probably looking for reduce:
$global_admins = $corporate_roles.reduce([]) |$admins, $hash| {
$hash['global_admin'] ? {
true => $admins << $hash['name'],
default => $admins
}
}

Create database seeder with same random value in a table row with Laravel database seeder

I am trying to create a table and populate the table with the following fields with the help of database seeder:
option a
option b
option c
option d
correct option
First four fields will be assigned random word, and the last field 'correct option' will contain any one of the first four.
I could not find any solution to do it with Laravel database seeder. Can anyone help?
Something like this?
use faker random element function in your factory or seeder.
$optionA = $faker->word;
$optionB = $faker->word;
$optionC = $faker->word;
$optionD = $faker->word;
return [
'option_a' => $optionA,
'option_b' => $optionB,
'option_c' => $optionC,
'option_d' => $optionD,
'correct_option' => $faker->randomElement([$optionA,$optionB,$optionC,$optionD]),
];
Create a factory and use Faker to generate the random words you're after
This sounds like an ideal use case for JSON columns (both for questions and answers). For instance, you might decide to have multiple valid answers to a single multiple choice question.
In your migration:
// create_questions_table.php
...
$table->json('choices')->default(new Expression('(JSON_ARRAY())'));
$table->json('answer')->default(new Expression('(JSON_ARRAY())'));
From https://laravel.com/docs/7.x/migrations#column-modifiers:
Using an Expression instance will prevent wrapping the value in quotes and allow you to use database specific functions. One situation where this is particularly useful is when you need to assign default values to JSON columns.
Then create a factory:
// QuestionFactory.php
$factory->define(Location::class, function (Faker $faker) {
$choices = $faker->words(4);
$answer = [ $choices[rand(1,4)] ];
return [
'choices' => $choices,
'answer' => $answer,
];
});
Using the Faker library included in Laravel, we can pick 4 words and randomly assign one of them to be the answer.

How to create a lookup in CakePHP

I'm in the process of converting a 10 year old PHP application. After my boss hired a php consultant, he has set up a CakePHP application environment and we are learning as we go. (fun, I know). Also, I come from a javascript/sharepoint background and have not had a lot of php experience.
As a test, I created a basic address table with these fields: firstname, lastname, state, phonenumber. I've been using justice league members as names and other test data to populate my table. Baked it just fine, default bootstrap pages are working.
I decided I wanted to add a dropdown field called current status, and for now just to keep it simple I wanted the choices: alive, dead.I created the column in my address table.
I created a second table called statuses and pointed the status column in my first table to the status table, using the status id as the foriegn key.
Baked my new table and rebaked my old one.
The status drop down does not give my choices of dead or alive, If I click in the field I get an up or down arrow, and based on which one you click, it either increments or decrements by 1. So the first time I click it inserts a 0. If I go up or down, it adds or takes away one.
I'm not sure what I'm doing wrong, I'm guessing there is some additional code I need to add to the MVC?
ok, if this works, then a lot is working :-). Now to the following: set in the Status Model a query like this:
public function getStatus()
{
$opt = $this->Status->find('list', array(...));
return $opt;
}
Then get the list over to the Adress Controller like this:
$this->loadModel('Status');
$opt => $this->Status->getStatus();
$this->set('opt', $opt);
Now you are able to access the $opt in the view file.
Just delete this line in the view:
$opts = array('0' => __('dead'), '1' => __('alive'));
And it should work.
Keep it simple. Ad to your table this row (only to understand how it works): 'status' as typ "tinyint(1)". Then set this in your view file:
$opts = array('0' => __('dead'), '1' => __('alive'));
When you create the inputfield, do it like that:
echo $this->Form->input('Address.status', array('options' => $opts, 'label'
=> __('Status')));
This should work.

Drupal 7 programmatically submit form

$form2_id = 'commerce_product_ui_product_form';
$form2_state['values'] = array(
'sku' => 'xyz100',
'title' => 'xyz',
'commerce_price' => '355',
'op' => t('Save Product')
);
drupal_form_submit($form2_id, $form2_state);
$form_errors = form_get_errors();
drupal_set_message('Form errors = '.$form_errors);
I get no errors but lots of warnings... and the data is not saved to the db.
call_user_func_array() expects parameter 1 to be a valid callback, function 'commerce_product_product_form' not found or invalid function name in drupal_retrieve_form()
You apparently are trying to programmatically submit values to a Drupal commerce generated form. This an unpractical approach, because of the modular achitecture of Drupal commerce: there are quite a few steps that populate a form before it is submitted, and even if you had (as you should have, anyway) prepoulate $form_state with drupal_get_form(), you would end up with errors in the submit function. I tried myself to fix your code, to no avail.
Fortunately, there is another approach, leveraging Drupal's entities, for which I must credit this post. You can create an entity metadata wrapper with a Drupal commerce's product object of your chosen type:
$wrapper = entity_metadata_wrapper('commerce_product',
commerce_product_new('[PRODUCT_TYPE_MACHINE_NAME]'));
By calling entity_metadata_wrapper this way, you create a property wrapper by which you can access a commerce_product entity; commerce_product_new('[PRODUCT_TYPE_MACHINE_NAME]') creates the entity instance with it's required defaults. Then you can do:
$wrapper->sku = 'xyz100';
$wrapper->title = 'xyz';
$wrapper->commerce_price->amount = 355;
$wrapper->commerce_price->currency_code = 'USD';
Be aware that commerce_price is a structured type, and amount and currency are required. amount must be in hundredths of the unit, so a 1.5$ price must be expressed as 150.
When your entity is fully populated with any other property, you need to issue
$wrapper->save();
When I first read your question I thought "this should be easy"... It wasn't and I spent a few hours to figure it out. It was worth the while, though, because I have found a much better solution to deal with entities (and nodes...) in Drupal.

Making one of a group of similar form fields required in CakePHP

I have a bunch of name/email fields in my form like this:
data[Friend][0][name]
data[Friend][1][name]
data[Friend][2][name]
etc.
and
data[Friend][0][email]
data[Friend][1][email]
data[Friend][2][email]
etc.
I have a custom validation rule on each one that checks to see if the corresponding field is filled in. Ie. if data[Friend][2][name] then data[Friend][2][email] MUST be filled in.
FYI, heres what one of the two rules look like:
My form validation rule: ( I have an email validation too but that's irrelevant here)
'name' => array(
'checkEmail' => array(
'rule' => 'hasEmail',
'message' => 'You must fill in the name field',
'last' => true
)
)
My custom rule code:
function hasEmail($data){
$name = array_values($data);
$name = $name[0];
if(strlen($name) == 0){
return empty($this->data['Friend']['email']);
}
return true;
}
I need to make it so that one of the pairs should be filled in as a minimum. It can be any as long as the indexes correspond.
I can't figure a way, as if I set the form rule to be required or allowEmpty false, it fails on ALL empty fields. How can I check for the existence of 1 pair and if present, carry on?
Also, I need to strip out all of the remaining empty [Friend] fields, so my saveAll() doesn't save a load of empty rows, but I think I can handle that part using extract in my controller. The main problem is this validation. Thanks.
I would have a look at the Model::beforeValidate callback (API).
Using this callback to output debug information should help you figure out how many times it fires and what data is available to the model on each call.
With this information, you could then create a flag when you find your first matching pair, and tamper with either the Model::validates array or the Model::data array to bypass subsequent validation attempts.
As for your last point, you may be able to use Set::filter to easily remove blank fields from your data set.

Resources