Array to DB::insert()->values(), which is in different order with the columns - arrays

Hi folks! I'm trying to transfer data as array from the controller to the model, and then paste the data into the query builder, but the data must be in the same order as specified in the columns.
What options do I have?
And do you think this is a bad practice?
Controller:
$responseNotes = Model::factory('Notes')-> createTicket([
'description' => htmlspecialchars($_POST['description']),
'contact_id' => $_POST['contact_id'],
'pref_contact' => $_POST['pref_contact'],
'dog_id' => $_POST['document_id'],
'type' => $_POST['type'],
'owner_id' => Auth::instance()->get_user()->id,
'cc' => $_POST['cc-emails'],
'title' => $_POST['title']
]);
Model:
public function createNote(array $data)
{
$columns = [
'type',
'owner_id',
'cc',
'title',
'description',
'contact_id',
'pref_contact',
'dog_id'
];
if (!array_diff($columns, array_keys($data))) {
// All needed values exists
$result = DB::insert($this->NOTES, $columns)-> values($data)-> execute($this->SCHEMA);
}
return ($result) ? $result : false ;
}

Thanks to this answer. Solved this by:
// Order $data array according to $column.values
$orderedData = [];
foreach ($columns as $key) {
$orderedData[$key] = $data[$key];
}
$result = DB::insert($this->TICKETS, $columns)
-> values($orderedData)
-> execute($this->SCHEMA);

Why you don't use ORM Model?
in controller:
$responseNotes = ORM::factory('Notes')-> values([
'description' => htmlspecialchars($_POST['description']),
'contact_id' => $_POST['contact_id'],
'pref_contact' => $_POST['pref_contact'],
'dog_id' => $_POST['document_id'],
'type' => $_POST['type'],
'owner_id' => Auth::instance()->get_user()->id,
'cc' => $_POST['cc-emails'],
'title' => $_POST['title']
])
try{
$responseNotes->save();
} catch (ORM_Validation_Exception $ex) {
print_r($ex->errors('models'));
}
And don't use htmlspecialchars($_POST['description'])
In model class modify function (doc):
public function filters()
{
return array(
'description' => array( array('htmlspecialchars') ),
);
}

It looks like You have associative array with structure db_column=>value right? Than You can simply insert like this:
DB::Insert('table_name',array_keys($data))->values(array_values($data))->execute();

Related

Update field in a Column on Laravel

I'm trying to update the status on my tickets table to the value : 2.
Once I can create the comment... (is working.. :) ), I wanted to change the status to 2.
This is my ticket model and the following function:
public function addComment($id,$body,$solved)
{
$this->find($id)->status = 2;
$this->save();
$this->comments()->create([
'ticket_id' => $id,
'body' => $body,
'user_id' => auth()->id()
]);
}
You need to get your object first then you can Update it:
public function addComment($id,$body,$solved)
{
$ticket = $this->find($id);
$ticket->status = 2;
$ticket->save();
$ticket->comments()->create([
'ticket_id' => $id,
'body' => $body,
'user_id' => auth()->id()
]);
}
Try changing your code like this. Maybe this will fix the problem you're having:
public function addComment($id,$body,$solved)
{
$ticket = Ticket::find($id);
$ticket->status = 2;
$ticket->save();
$ticket->comments()->create([
'ticket_id' => $id,
'body' => $body,
'user_id' => auth()->id()
]);
}

Cakephp 3 search query, with concat

I'm trying to perform a search on two joined columns, fname and lname.
This does not appear to be working:
Object of class Cake\Database\Expression\FunctionExpression could not be converted to string
$users = $this->Users->find();
$users->select(['id', 'fname', 'lname'])
->where([$users->func()->concat(['fname', 'lname']).' LIKE' => $terms]);
Any ideas?
Thanks.
If you're concatenating first and last names, they should be concatenated with spaces in between.
$users->select(['id', 'fname', 'lname'])
->where(function ($exp, $query) use ($terms) {
$conc = $query->func()->concat([
'fname' => 'identifier', ' ',
'lname' => 'identifier'
]);
return $exp->like($conc, $terms);
});
Yu have to use query expression but this can't be done in a pagination array.
So Following ndn suggestion here's how I would do
create a custom finder. In your UsersTable file
public function findByKeyword(Query $query, array $options)
{
$keyword = $options['keyword'];
$query->where(
function ($exp, $q) use($keyword){
$conc = $q->func()->concat([
'Users.fname' => 'literal', รน
'Users.lname' => 'literal']);
return $exp
->or_([
'Users.fname LIKE' => "%$keyword%",
'Users.lname LIKE' => "%$keyword%",
])
->like($conc, "%$keyword%");
}
);
return $query;
}
Controller
$this->paginate = [
'finder' => [
'byKeyword' => [
'keyword' => $this->request->data['Users']['keyword']
]],
'conditions' => $limo, // this will merge your $limo conditions
// with the ones you set in the custom finder
'order'= > ['Users.fname desc'],
];
$this->set('userlist', $this->paginate($this->Users));
I think you have to use SQL expressions. Try something like this:
->where(function ($exp, $q) use($terms) {
$concat = $q->func()->concat([
'fname' => 'identifier',
'lname' => 'identifier'
]);
return $exp->like($concat, $terms);
});

cakephp cakedc between

I'd like to use the 'between' example from cakedc, but just can't make sense out of it.
'range' => array('type' => 'expression', 'method' => 'makeRangeCondition', 'field' => 'Article.views BETWEEN ? AND ?'),
I have field qca_start in my table and want user to provide two values (from, to) and search for qca_start between from and to.
My controller:
(I've used other simpler searches without problem. (employee_id works just fine here)
public $presetVars = array(
array('field' => 'employee_id', 'type' => 'value'),
array('field' => 'qca_start', 'type' => 'value') // not sure what type to use here for between search.
};
The field on my table is qca_start, not user how would i name the presetVar for this?
On my model
public $filterArgs = array(
array('name' => 'employee_id', 'type' => 'value'),
'range' => array('type' => 'expression', 'method' => 'makeRangeCondition', 'field' => 'Article.views BETWEEN ? AND ?'),
);
I don't know how to format this for filterArgs:
'range' => array('type' => 'expression', 'method' => 'makeRangeCondition', 'field' => 'Article.views BETWEEN ? AND ?'),
I want qca_start to be between search values One and Two.
Can you help?
a copy/paste from the answer i gave # CakeDC Plugin Search Between Dates
in model :
'creationDateBetween' => array(
'type' => 'expression',
'method' => 'CreationDateRangeCondition',
'field' => 'MODEL.creationdate BETWEEN ? AND ?',
),
public function CreationDateRangeCondition($data = array()){
if(strpos($data['creationDateBetween'], ' - ') !== false){
$tmp = explode(' - ', $data['creationDateBetween']);
$tmp[0] = $tmp[0]."-01-01";
$tmp[1] = $tmp[1]."-12-31";
return $tmp;
}else{
return array($data['creationDateBetween']."-01-01", $data['creationDateBetween']."-12-31");
}
}
in view : note that i'm using a slider for year range
echo $this->Form->input('creationDateBetween',
array(
'label' => __('Creation date between X and Y'),
'div' => false,
'style' => 'border: 0; color: #49AFCD; font-weight: bold;'
)
);
?><div id="creationDateBetweenSlider" style="padding:0;"></div><?php
<script>
$(function() {
var creationDateBetweenSlider = $( "#creationDateBetweenSlider" ),
institutionCreationDateBetween = $( "#MODELCreationDateBetween" ),
lock = 0;
creationDateBetweenSlider.slider({
range: true,
min: 1900,
max: 2050,
values: [ 2000, 2013 ],
slide: function( event, ui ) {
MODELCreationDateBetween.val( ui.values[ 0 ] + " - " + ui.values[ 1 ] );
}
});
if(lock != 0) MODELCreationDateBetween.val( creationDateBetweenSlider.slider( "values", 0 ) + " - " + creationDateBetweenSlider.slider( "values", 1 ) );
lock = 1;
});
</script>
waiting for feedback to see if it works for you ;)
You should read the documenation # https://github.com/cakedc/search
'expression' type useful if you want to add condition that will
generate by some method, and condition field contain several parameter
like in previous sample used for 'range'. Field here contains
'Article.views BETWEEN ? AND ?' and Article::makeRangeCondition
returns array of two values.
So just return 2 values in your method:
public function makeRangeCondition() {
...
return array($from, $to);
}
They will automatically replace the two ? in this order then.

Custom Field with autcomplete

I am trying to build my own node reference custom field - I know several projects out there already do this, I am building this in order to learn... :)
My problem is the autocomplete path, it's not being triggered, I have checked the noderefcreate project and implemented my solution based on that project. But still; nothing is being triggered when I check firebug.
Here is my code:
function nodereference_field_widget_info() {
return array(
'nodereference_nodereference_form' => array(
'label' => t('Node Reference Form'),
'field types' => array('nodereference'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
'settings' => array(
'autocomplete_match' => 'contains',
'autocomplete_path' => 'nodereference/autocomplete',
),
),
);
}
function nodereference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
if ($instance['widget']['type'] == 'nodereference_nodereference_form') {
$widget = $instance['widget'];
$settings = $widget['settings'];
$element += array(
'#type' => 'textfield',
'#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
'#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'],
);
}
return array('nid' => $element);
}
You need to define method from where auto compete will take suggestions.
It can be done like this:
/**
* implements hook_menu
*/
function your_module_name_menu() {
$items['master_place/autocomplete'] = array(
'page callback' => '_your_module_name_autocomplete',
'access arguments' => array('access example autocomplete'),
'type' => MENU_CALLBACK
);
return $items;
}
/**
* Auto complete method implementation
* #param $string
*/
function _your_module_name_autocomplete($string) {
$matches = array();
// Some fantasy DB table which holds cities
$query = db_select('target_db_table', 'c');
// Select rows that match the string
$return = $query
->fields('c', array('target_column'))
->condition('c.target_column', '%' . db_like($string) . '%', 'LIKE')
->range(0, 10)
->execute();
// add matches to $matches
foreach ($return as $row) {
$matches[$row->city] = check_plain($row->city);
}
// return for JS
drupal_json_output($matches);
}

cakephp beforeSave callback in Behaviors don't save data correctly

Controller:
$data =
array(
'ContentI18n' =>
array(
0 =>
array(
'title' => 'first',
'author' => 'first',
'source' => 'sgfsdfrst',
'lang' => 'fa',
),
),
'Content' =>
array(
'publish' => 1,
'type' => 3,
'pages' => 8,
'volume' => 7,
'modified' => '2012-05-27 14:16:37',
'created' => '2012-05-27 14:16:37',
'lang' => 'fa',
),
);
$this->Content->create();
$this->Content->saveAll($data);
Model:
public $hasMany = array(
'ContentI18n' => array(
'className' => 'ContentI18n',
)
);
beforeSave function in behavior:
public function beforeSave(Model $model) {
// Define the new Translate model
App::uses($model->name . 'I18n', 'Model');
$varI18n = $model->name . 'I18n';
$modelI18n = new $varI18n;
foreach ($model->data[$model->name] as $key => $data) {
if (!in_array($key, $this->setting))
$modelData[$model->name][$key] = $data;
else
$modelData[$model->name . 'I18n'][0][$key] = $data;
}
$modelData[$model->name . 'I18n'][0]['lang'] = $model->locale;
$modelData[$model->name]['lang'] = $model->locale;
$model->data = $modelData;
//pr($model->data);
return TRUE;
}
every things seems be cause when is save it directly it's save with saveAll. but when i use same structure of data in behavior did not work without any error.
I found out that beforeSave callback will not trigger by saveAll. for executing some code before saveAll we must override saveAll function in our model.
public function saveAll($data, $options = array()) {
/*
your code you want execute before saving...
*/
parent::saveAll($data, $options);
}
for other saving methods such as saveMany,saveAssociated,... beforeSave trigger by them.

Resources