How to create subtraction with expression objects? - cakephp

How can I get the proper result for TotalQt?
$query = $this->ItemLedgers
->find()
->where([
'ItemLedgers.processed_on <=' => date("Y-m-d",strtotime($to_date))
]);
$totalInCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['in_out' => 'In']),
$query->newExpr()->add(['quantity']),
'integer'
);
$totalOutCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['in_out' => 'Out']),
$query->newExpr()->add(['quantity']),
'integer'
);
$query
->select([
'total_in' => $query->func()->sum($totalInCase),
'total_out' => $query->func()->sum($totalOutCase),
'id',
'item_id',
'TotalQt' => $query->func()->sum($totalInCase) - $query->func()->sum($totalOutCase),
])
->contain(['Items' => function ($q) use($where) {
return $q
->where($where)
->contain(['Units']);
}])
->where(['company_id' => $st_company_id])
->group('item_id')
->autoFields(true)
->where($where);

Related

Where orWhere Laravel 5.5 logical DB issue

I am in agony
This is my helper
$friend_query = Friend::where([
'user_id' => Auth::id(),
'friend_id' => $friend_id,
])->orWhere([
'user_id' => $friend_id,
'friend_id' => Auth::id(),
])->first();
$friendship = new stdClass();
$friendship->exist = false;
$friendship->accepted = false;
if (! is_null($friend_query))
{
$friendship->accepted = $friend_query->accepted;
$friendship->exist = true;
}
var_dump($friendship->exist);
exit;
return $friendship;
And when I am logged as 'user_id' => auth::id() - everything is fine but when I am logged as 'friend_id' who got request always var_dump return me true... This is third day I can not find solution. The photo of DB included in post.
When you want to "group" your where clauses, you should pass a closure instead then perform your condition inside it. Say for example, you want your query to look like this
SELECT * FROM friends WHERE (user_id = ? AND friend_id = ?) OR (user_id = ? AND friend_id = ?) LIMIT 1
Then the eloquent version of this would be
$friend_query = Friend::where(function ($query) use ($friend_id) {
$query->where('user_id', Auth::id())
->where('friend_id', $friend_id);
})->orWhere(function ($query) use ($friend_id) {
$query->where('friend_id', Auth::id())
->where('user_id', $friend_id);
})->first();
Thank you,
just little syntax error should be
->orWhere(function ($query) {
but there is one problem - Undefined variable: friend_id
it goes like this
function friendship($friend_id){
friend_query = Friend::where([
'user_id' => Auth::id(),
'friend_id' => $friend_id,
])->orWhere(function ($query) {
$query->where([
'user_id' => $friend_id,
'friend_id' => Auth::id(),
]);
})
->first();
... }
Try it like this :
$friend_query = Friend::where([
'user_id' => Auth::id(),
'friend_id' => $friend_id,
])
->orWhere(function ($query) use($friend_id) {
$query->where([
'user_id' => $friend_id,
'friend_id' => Auth::id(),
]);
})
->first();

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

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();

How to filter containments by associated data?

I want to get associated only if the second level associated data respect the given condition.
The query will maybe better explain what I try to do.
$selSite = $this->Sites->get($selSiteId, [
'contain' => [
'Agplans.Products' => function ($q) {
return $q
->where([
'Products.type' => 'hosting',
]);
}
]
]);
So I expect an agplan only if its associated product matches the condition.
But the result is:
'agplans' => [
(int) 0 => object(App\Model\Entity\Agplan) {
'id' => (int) 20,
'product_id' => (int) 4,
'product' => null,
...,
},
(int) 1 => object(App\Model\Entity\Agplan) {
'id' => (int) 21,
'site_id' => (int) 64,
'product_id' => (int) 75,
'product' => object(App\Model\Entity\Product) {
'id' => (int) 75,
...,
},
...,
}
],
My problem here is to get agplan[0] with a product => null.
It's not what I understood from the doc.
How to get the agplan with 'product' => object(App\Model\Entity\Product) only?
So thanks to what #ndm pointed me out I understood that I have to build my query like that:
$selSite = $this->Sites->get($selSiteId, [
'contain' => [
'Agplans.Products',
'Agplans' => function ($q) {
return $q
->matching('Products', function ($q) {
return $q
->where([
'type' => 'hosting',
]);
});
}
]
]);
That way, I only get agplans matching the given product.
Anyway, I find the CakePHP doc not clear on the contain feature about restricting associated.

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);
});

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);
}

Resources