well i'm confused on how to insert "Checkboxes" values to SQL
here's my code
$form['last'] = array(
'#type' => 'checkboxes',
'#title' => "Just title",
'#options' => array(
'opt1' => "Option 1",
'opt2' => "Option 2",
),
as you can see my form consist of two checkbox, so how to get the value and insert to sql language. anyone can give an example or hint
here the method that i'm used to get the value (i know its very wrong)
function fasil_form_submit($form,&$form_state){
global $user;
$entry = array(
'uid' => $user->uid,
'test1' => $form_state['values']['1first'],
$jenis = 'aa_test';
$return = insert_form($entry,$jenis);
}
ps : sorry for my bad english
I'm not 100% sure what you're trying to do but I think you're trying to insert a value in the database for each of the checkboxes ticked? If so this is the quickest way:
function fasil_form_submit($form,&$form_state){
// Filter out un-checked items
$checked = array_filter($form_state['values']['last']);
global $user;
foreach ($checked as $value) {
$entry = array(
'uid' => $user->uid,
'test1' => $value
);
$jenis = 'aa_test';
insert_form($entry, $jenis);
}
}
As already mentioned in another answer the simplest way to see what you need to get from the form is to output $form_state['values'] in your submission function to see what was passed from the form.
However, rather than use the unsightly print_r and potentially messing up the form submission by calling exit prematurely (in Drupal 7 drupal_exit() should always be used instead of exit anyway), I strongly recommend you download and install the Devel module and use it's dpm() function to print the variable to the screen.
Any variable passed to dpm() is outputted to the standard Drupal messages area, and becomes an easy to navigate on-screen hierarchy of that variable like this:
You can use it absolutely anywhere in code within Drupal, e.g.
function fasil_form_submit($form,&$form_state){
// Output the form submission array to the messages area:
dpm($form_state['values']);
}
The Devel module is very good, and absolutely essential for any serious Drupal development.
Hope that helps.
Here's a quick way I like to look at my form output
function fasil_form_submit($form,&$form_state){
header('content-type: Text/plain');
print_r($form_state['values']);
exit;
global $user;
$entry = array(
'uid' => $user->uid,
'test1' => $form_state['values']['1first'],
$jenis = 'aa_test';
$return = insert_form($entry,$jenis);
}
Now those 3 lines should make it clear how Drupal is submitting the data.
I believe you will need to loop through $form_state['values']['last'] and test that the key is not set to 0.
function fasil_form_submit($form,&$form_state){
global $user;
foreach ($form_state['values']['last'] as $key => $value) {
if (value != 0) {
// $form_state['values']['last'][$key] was checked
}
else {
// $form_state['values']['last'][$key] not checked
}
}
}
Related
I started fiddling with Prestashop 1.7 modules and I ran into this weird behavior.
I have this code to save values from form post to database (working ok)
protected function postProcess()
{
$form_values = $this->getConfigFormValues();
foreach (array_keys($form_values) as $key) {
Configuration::updateValue($key, Tools::getValue($key));
if($key == 'MSLT_MEGAMENU_CATEGORIES'){
$categories = implode(",",Tools::getValue($key));
Configuration::updateValue('MSLT_MEGAMENU_CATEGORIES', $categories);
}else{
$this->errors[]=$this->l('Please select categories to display');
}
}
}
And I use this code to fetch those values from database (works ok)
protected function getConfigFormValues()
{
$categories = explode(',',Configuration::get('MSLT_MEGAMENU_CATEGORIES', true));
return array(
'MSLT_MEGAMENU_LIVE_MODE' => Configuration::get('MSLT_MEGAMENU_LIVE_MODE', true),
'MSLT_MEGAMENU_CATEGORIES' => $categories,
'MSLT_MEGAMENU_ACCOUNT_EMAIL' => Configuration::get('MSLT_MEGAMENU_ACCOUNT_EMAIL', 'contact#prestashop.com'),
'MSLT_MEGAMENU_ACCOUNT_PASSWORD' => Configuration::get('MSLT_MEGAMENU_ACCOUNT_PASSWORD', null),
);
}
and helper to populate form with values
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFormValues(), /* Add values for your inputs */
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id,
);
return $helper->generateForm(array($this->getConfigForm()));
This is the var_dump() when trying to load values from database, for this case my DB value is (1,3,9)
array(1) { [0]=> string(1) "9" }
As you can see Configuration::get() only gets the last string value.
Interesting behavior is that when I update the data and stay in the same page, then everything is ok and data is fetched properly, but when I leave module configuration page and comeback, the issue happens. Maybe I am missing some little snippet of code? I am still a newbie. If needed I can provide more code.
I don't know what your specific goal is but in any case it is always convenient to use Prestashop's own functions.
To save and select the configuration variables
eg, save values in json format
Configuration::updateValue('MYVALUES', Tools::jsonEncode(Tools::getValue('MYVALUES')), true );
eg, get values
Tools::jsonDecode( Configuration::get( 'MYVALUES' );
Dirty workaround I found to get imploded values from DB correctly. Maybe someone will use it.
$sql = 'SELECT * FROM '._DB_PREFIX_.'configuration WHERE name = "MSLT_MEGAMENU_SELECTED_CAT"';
$value = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow($sql);
$selected = explode(',',$value['value']);
CakePHP 3.7
I'm trying to generate a query which uses a WHERE...OR pattern. The equivalent in MySQL - which executes and gives the results I want is:
SELECT * FROM groups Groups WHERE (regulation_id = 1 AND label like '%labelling%') OR (id IN(89,1,8,232,228,276,268,294));
I've read the Advanced Conditions (https://book.cakephp.org/3.0/en/orm/query-builder.html#advanced-conditions) part of the documentation but can't generate that query.
Assume the Table class is Groups I have this:
$Groups = TableRegistry::getTableLocator()->get('Groups');
$groups_data = $Groups->find('all')->where(['regulation_id' => 1);
$groups_data = $groups_data->where(['label LIKE' => '%labelling%']);
This produces the first segment of the WHERE statement, i.e.
SELECT * FROM groups Groups WHERE (regulation_id = 1 AND label like '%labelling%')
However I can't see how to attach the OR condition, especially since orWhere() is deprecated.
So I've tried this - which is even given as an example in the docs:
$in_array = [89,1,8,232,228,276,268,294]; // ID's for IN condition
$groups_data = $groups_data->where(['OR' => ['id IN' => $in_array]]);
But this just appends an AND to the inside of my existing SQL:
SELECT * FROM groups Groups WHERE (regulation_id = 1 AND label like '%labelling%' AND id IN(89,1,8,232,228,276,268,294);
Which does not yield the correct results as the syntax isn't what's required to run this query.
How do you "move out" of the WHERE and append an OR condition like in the vanilla query?
I made several attempts using QueryExpression as per the docs, but all of these produced PHP Fatal Errors saying something to do with the Table class - I doubt this was on the right lines anyway.
"moving out" is a little tricky, you have to understand that internally the conditions are pushed into a \Cake\Database\Expression\QueryExpression object which by default uses AND to concatenate the statements, so whatever you push on to that, will be added using AND.
When you create OR statements, being it implicitly with the shown nested array syntax, or explicitly by using the expression builder, this creates a separate, self-contained expression, where its parts are being concatenated using OR, it will compile itself (and since there's only one condition, you don't see any OR's), and the result will be used in the parent expression, which in your case is the main/base expression object for the queries where clause.
Either pass the whole thing at once (being it via array syntax or expressions), eg:
$groups_data->where([
'OR' => [
'AND' => [
'regulation_id' => 1,
'label LIKE' => '%labelling%'
],
'id IN' => $in_array
]
]);
and of course you could build that array dynamically if required, or, if you for some reason need to use separate calls to where(), you could for example overwrite the conditions (third parameter of where()), and include the current ones where you need them:
$groups_data->where(
[
'OR' => [
$groups_data->clause('where'),
'id IN' => $in_array
]
],
[],
true
);
I know this issue is old but maybe someone is looking. Here is my solution:
protected $_hardValues= array(
'company_id' => $company_from_session;
);
function beforeFind($event=null, $query = null, $options = null, $primary = true){
$conds = [];
$columns = $this->getSchema()->columns();
foreach( $this->_hardValues as $field => $value){
if( !is_null($value) && in_array($field, $columns) ){
$conds[$this->_alias . '.' . $field] = $value;
}
}
if( empty( $conds)) return true;
$where = $query->clause('where'); //QueryExpression object;
if( empty( $where)){
$query->where($conds);
}else{
$where->add($conds);
}
}
As of CakePHP 4.x, the documented way of doing this is:
$query = $articles->find()
->where([
'author_id' => 3,
'OR' => [['view_count' => 2], ['view_count' => 3]],
]);
See documentation
I have a problem, right now Im using this foreach loop on CakePhp on which I want to add all the values which are still not on the table for the respecting user. To give a little more context, the user has a menu. And the admin can select which one to add for the user to use. On the next code I receive a array with the menus which will be added as so:
//This is what comes on the ['UserMenuAccessibility'] array:
Array ( [menu_accessibility_id2] => 2 [menu_accessibility_id3] => 3 [menu_accessibility_id4] => 4 [menu_accessibility_id5] => 5 [menu_accessibility_id8] => 8 )
I get the ids of the menus which want to be added to the table for the user to use. And I use the next code to add the menus to the table if they are not there still:
//I check if the array has something cause it can come with no ids.
if (!(isset($this->request->data['UserMenuAccessibility']))) {
$this->request->data['UserMenuAccessibility'] = array();
}
$UserMenuAccessibility = $this->request->data['UserMenuAccessibility'];
foreach ($UserMenuAccessibility as $key => $value) {
$conditions = array(
'UserMenuAccessibility.menu_accessibility_id' => $value,
'UserMenuAccessibility.users_id' => $id
);
if ($this->User->UserMenuAccessibility->hasAny($conditions)) {
} else {
$valuemenu['UserMenuAccessibility']['users_id'] = $id;
$valuemenu['UserMenuAccessibility']['menu_accessibility_id'] = $value;
if ($this->User->UserMenuAccessibility->save($valuemenu)) {
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
For some reason the array is only saving the last new id which is not on the table and not the rest. For example if I have menu 1 and 2 and add 3 and 4 only 4 gets added to the table. For some reason I cant add all the missing menu ids to the table. Any ideas why this is happening?
Thanks for the help on advance.
It looks like your code will save each item, but each call to save() is overwriting the last entry added as $this->User->UserMenuAccessibility->id is set after the first save and will be used for subsequent saves. Try calling $this->User->UserMenuAccessibility->create() before each save to ensure that the model data is reset and ready to accept new data:-
$valuemenu['UserMenuAccessibility']['users_id'] = $id;
$valuemenu['UserMenuAccessibility']['menu_accessibility_id'] = $value;
$this->User->UserMenuAccessibility->create();
if ($this->User->UserMenuAccessibility->save($valuemenu)) {
}
In cakephp 2.0 $this->Model->create() create work fine. But if you are using cakephp version 3 or greater then 3. Then follow the below code
$saveData['itemId'] = 1;
$saveData['qty'] = 2;
$saveData['type'] = '0';
$saveData['status'] = 'active';
$saveData = $this->Model->newEntity($saveData);
$this->Model->save($materialmismatch);
In normal case we use patchEntity
$this->Model->patchEntity($saveData, $this->request->data);
It will only save last values of array so you have to use newEntity() with data
In cakephp3, patchEntity() is normally used. However, when using it for inserting-new/updating entries in a foreach loop, I too saw that it only saves the last element of the array.
What worked for me was using patchEntities(), which as explained in the patchEntity() doc, is used for patching multiple entities at once.
So simplifying and going by the original code sample to handle multiple entities, it could be:
$userMenuAccessibilityObject = TableRegistry::get('UserMenuAccessibility');
foreach ($UserMenuAccessibility as $key => $value) {
$userMenuAccessibility = $userMenuAccessibilityObject->get($value);//get original individual entity if exists
$userMenuAccessibilities[] = $userMenuAccessibility;
$dataToPatch = [
'menu_accessibility_id' => $value,
'users_id' => $id
]//store corresponding entity data in array for patching after foreach
$userMenuAccessibilitiesData[] = $dataToPatch;
}
$userMenuAccessibilities = $userMenuAccessibilityObject->patchEntities($userMenuAccessibilities, $userMenuAccessibilities);
if ($userMenuAccessibilityObject->saveMany($requisitions)) {
} else {
$this->Session->setFlash(__('The users could not be saved. Please, try again.'));
}
Note: I haven't made it handle if entity doesn't exist, create a new one and resume. That can be done with a simple if condition.
I am using a form with several check boxes i need to display only those data which is in check box category.
How to write conditions for that.
for($i=0;$i<count($this->request->data['filter']['delivering']);$i++)
{
$opt1=".'Gig.bangsalsodeliverings' => ".$this->request->data['filter']['delivering'][$i];
$opt2=$opt2.$opt1.',';
}
$options=array('conditions' => array($opt2));
$this->Paginator->settings = $options;
$agetGigsItem = $this->Paginator->paginate('Gig');
But getting error.
Thanks in advance
It seems you're using a string contatenation instead of array to build the conditions array.
Also it's not clear to me if the filter delivering is a set of strings or integers.
I guess you can try:
// Merge the filters into a csv string
$filters = array();
foreach($this->request->data['filter']['delivering'] as $v){
$filters[] = "'{$v}'";
}
$csv_filters = implode(",", $filters);
// Use the csv to make a IN condition
$this->Paginator->settings = array('conditions' => array(
"Gig.bangsasodeliverings IN ({$csv_filters})",
));
Please note that sql injection can be made here, so prepare your data before creating $csv_filters.
OK, this is the situation. In my beforeSave function I want to manipulate some $this->request->data entries.
This is my component:
<?php
App::uses('Component', 'Controller');
class GetStationComponent extends Component {
public function getStationId ($station) {
$stationInstance = ClassRegistry::init('Station');
$conditions = array('OR' => array(
array('Station.code LIKE' => $station),
array('Station.naam LIKE' => $station),
array('Station.naam_overig LIKE' => $station)
));
$result = $stationInstance->find('list', array('conditions'=>$conditions));
$value = array_values($result);
$value = $value[0];
return $value;
}
}
?>
And this is my beforeSave function in my Controller:
public function beforeSave($options = array()) {
if (!empty($this->request->data['Experience']['vertrekstation']) && !empty($this->request->data['Experience']['aankomststation'])) {
$this->request->data['Experience']['vertrekstation'] = $this->GetStation->getStationId($this->request->data['Experience']['vertrekstation']);
$this->request->data['Experience']['aankomststation'] = $this->GetStation->getStationId($this->request->data['Experience']['aankomststation']);
}
return true;
}
It should return an ID of the stations name. But in the Database the name itself is stored (which is filled in by the user) instead of the ID. What do I need to change in my Component (I guess...) to return the right values?
(P.S. The query itself in the component returns an ID, because at first I'd put the 'beforeSave' directly into my function which saves the data, but then my validation error said that it wasn't a right value. Which is correct...)
To complement the other answers; to get just the value of a single field, use Model::field()
return $stationInstance->field('id', $conditions);
It is best to add a sort order to this statement to make sure that the results will always be returned in the same order:
return $stationInstance->field('id', $conditions, 'code ASC');
Since you only perform a single query on the Model, and don't do anything afterwards, you don't even need the intermediate $stationInstance variable. Your code can be further simplified to:
return ClassRegistry::init('Station')->field('id', $conditions, 'code ASC');
Some observations
Because of the 'fuzzy' matching on the name of the station, the first result may not always be the station intended by the user it's best to offer an 'autocomplete' functionality in your front-end and have the user pick the correct station (e.g. To prevent picking Den Haag when the user meant Den Haag HS)
If the station does not fully matches a station, you should present a warning that the station wasn't found
You didn't surround your search-terms with % for the LIKE queries. If you intend to search for 'name "contains", you should use '%' . $station . '%'. For "starts with" use $station . '%'
As #mark suggested; beforeSave() is a callback of the Model and should be located there.
Also; beforeSave() is triggered after validation has taken place, so it will probably be too late. beforeValidate() is the best callback for this
If the Experience model is already attached to the Station model, you don't need to use a component, because you can directly access the Station model. It's best to put the search-method inside the Station model;
Moving it all to the right(*) location
*) Other options are always possible, this is just a possible approach
Add the 'search' method to the Station-model;
app/Model/Station.php
public function getStationIdByName($name)
{
$name = trim($name);
if (empty($name)) {
return null;
}
$name = '%' . $name . '%';
$conditions = array(
'OR' => array(
array($this->alias . '.code LIKE' => $name),
array($this->alias . '.naam LIKE' => $name),
array($this->alias . '.naam_overig LIKE' => $name),
)
);
return $this->field('id', $conditions, 'code ASC');
}
..and use it in the Experience Model
app/Model/Experience.php
public function beforeValidate(array $options = array())
{
if (
!empty($this->data[$this->alias]['vertrekstation'])
&& !empty($this->data[$this->alias]['aankomststation'])
) {
// Directly access the Station-model from within the Experience Model
$this->data[$this->alias]['vertrekstation']
= $this->Station->getStationIdByName($this->data[$this->alias]['vertrekstation']);
$this->data[$this->alias]['aankomststation']
= $this->Station->getStationIdByName($this->data[$this->alias]['aankomststation']);
}
// Call parent-callback after setting the values
return parent::beforeValidate($options);
}
[UPDATE] Using the Conventions, prevent unwanted behavior
After writing the previous example, I noticed there are some flaws in your current setup;
If vertrekstation and aankomststation should hold the 'foreign key' of the station (the station-id) they are not named according to the CakePHP Model and Database Conventions
Because of 1) By putting this code inside the beforeValidate(), it will also be triggered when updating an existing record. Because you're using the aankomststation and vertrekstation field both to hold the name of the station (inside the Form) and the id (inside the database), the Model will attempt to look-up the station-id via the id when updating. NOTE that inside the form you'll still be using vertrekstation and aankomstation as field-name. These field names are not present in your database, and therefore will not be able to directly update data inside your database, that's where the beforeValidate() callback is used for
Because the Experience model needs two relations to the Station model (once as departure station ('vertrekstation'), once for arrival station ('aankomststation')), you will need an alias for the Station-model. See: Multiple relations to the same model
app/Model/Experience.php
class Experience extends AppModel {
/**
* Station will be associated to the 'Experience' Model TWICE
* For clarity, using an 'alias' for both associations
*
* The associated Models will be accessible via;
* $this->DepartureStation
* $this->ArrivalStation
*
* To stick to the CakePHP conventions, name the foreign keys
* accordingly
*/
public $belongsTo = array(
'DepartureStation' => array(
'className' => 'Station',
'foreignKey' => 'departure_station_id',
),
'ArrivalStation' => array(
'className' => 'Station',
'foreignKey' => 'arrival_station_id',
)
);
public function beforeValidate(array $options = array())
{
// vertrekstation and aankomststation hold the 'names' of the
// stations and will only be present if the form has been submitted
if (
!empty($this->data[$this->alias]['vertrekstation'])
&& !empty($this->data[$this->alias]['aankomststation'])
) {
// Directly access the Station-model from within the Experience Model
// using the *aliases*
$this->data[$this->alias]['departure_station_id']
= $this->DepartureStation->getStationIdByName($this->data[$this->alias]['vertrekstation']);
$this->data[$this->alias]['arrival_station_id']
= $this->ArrivalStation->getStationIdByName($this->data[$this->alias]['aankomststation']);
// Invalidate the vertrekstation and aankomststation fields if lookup failed
if (empty($this->data[$this->alias]['departure_station_id'])) {
// Unable to find a station. Mark the Form-field invalid
$this->invalidate('vertrekstation', __('A station with this name was not found'));
}
if (empty($this->data[$this->alias]['arrival_station_id'])) {
// Unable to find a station. Mark the Form-field invalid
$this->invalidate('aankomststation', __('A station with this name was not found'));
}
}
// Call parent-callback after setting the values
return parent::beforeValidate($options);
}
}
The find('list') option of Cake returns an array like
array( 1 => 'name1',
3 => 'name2',
//etc...
)
where the index is the id and the value is the display field you set on the model.
So, when you do $value = array_values($result);, you're extracting the values of the array (meaning, the display fields). I'm assuming you're not using the id as the displayField, so that's why it's returning the names and not the id.
I'm not sure why you're using find('list') instead of find('first') or other alternative, but if you don't want to modify that for whatever reason, the fix that should return the first id obtained by the search is
reset($result); //possibly not needed, but just in case
$value = key($result );
First you must understand how Cake works
There is no $this->request in your models. Its part of the controller.
In your model your passed data will be in $this->data directly.
public function beforeSave($options = array()) {
parent::beforeSave($options); // you also forgot the parent call
if (!empty($this->data[$this->alias]['vertrekstation']) && ...)) {
$this->data[$this->alias]['vertrekstation'] = ...;
}
return true;
}
Your find call also looks pretty screwed up. I dont know what you want to do.
But I strongly advice you to use debug() etc to find out what is returned and correct your code accordingly.
You probably need find(first) if you are only interesting in a single value.