Using function max cakephp in query - cakephp

Hello everyone como estan will see I have this query in SQL
SELECT MAX(id_alternativa) FROM pregunta_alternativa WHERE id_pregunta = 7
which I'm doing in cakephp using the MAX function framework
public function register() {
$query = $this->PreguntasAlternativas->find()
->select([
'id_alternativa' => $query->func()->max(['id_alternativa'])
])->where(['id_pregunta' => '7']);
$this->set('alternatives',$query); }
but it shows this is the message Error
Error: Call to a member function func() on null File C:\xampp\htdocs\serapp\src\Controller\PreguntasAlternativasController.php Line: 14
as I see documentation so their functions are used
Sql Functions Cakephp
thanks for helping me

the solution was simple place it here, referring to the documentation
public function register() {
$query = $this->PreguntasAlternativas->find();
$query->select(['id_alternativa' => $query->func()->max('id_alternativa')
])->where(['id_pregunta' => '7']);
You must be setear variable $query

Related

Indirect modification of overloaded element of Illuminate\Support\Collection has no effect

im quite new in laravel framework, and im from codeigniter.
I would like to add new key and value from database
static function m_get_promotion_banner(){
$query = DB::table("promotion_banner")
->select('promotion_banner_id','promotion_link','about_promotion')
->where('promotion_active','1')
->get();
if($query != null){
foreach ($query as $key => $row){
$query[$key]['promotion_image'] = URL::to('home/image/banner/'.$row['promotion_banner_id']);
}
}
return $query;
}
that code was just changed from codeigniter to laravel, since in codeigniter there are no problem in passing a new key and value in foreach statement
but when i tried it in laravel i got this following error :
Indirect modification of overloaded element of Illuminate\Support\Collection has no effect
at HandleExceptions->handleError(8, 'Indirect modification of overloaded element of Illuminate\Support\Collection has no effect', 'C:\xampp\htdocs\laravel-site\application\app\models\main\Main_home_m.php', 653, array('query' => object(Collection), 'row' => array('promotion_banner_id' => 1, 'promotion_link' => 'http://localhost/deal/home/voucher', 'about_promotion' => ''), 'key' => 0))
please guide me how to fix this
thank you (:
The result of a Laravel query will always be a Collection. To add a property to all the objects in this collection, you can use the map function.
$query = $query->map(function ($object) {
// Add the new property
$object->promotion_image = URL::to('home/image/banner/' . $object->promotion_banner_id);
// Return the new object
return $object;
});
Also, you can get and set the properties using actual object properties and not array keys. This makes the code much more readable in my opinion.
For others who needs a solution you can use jsonserialize method to modify the collection.
Such as:
$data = $data->jsonserialize();
//do your changes here now.
The problem is the get is returning a collection of stdObject
Instead of adding the new field to the result of your query, modify the model of what you are returning.
So, assuming you have a PromotionBanner.php model file in your app directory, edit it and then add these 2 blocks of code:
protected $appends = array('promotionImage');
here you just added the custom field. Now you tell the model how to fill it:
public function getPromotionImageAttribute() {
return (url('home/image/banner/'.$this->promotion_banner_id));
}
Now, you get your banners through your model:
static function m_get_promotion_banner(){
return \App\PromotionBanner::where('promotion_active','1')->get();
}
Now you can access your promotionImage propierty in your result
P.D:
In the case you are NOT using a model... Well, just create the file app\PromotionImage.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PromotionImage extends Model
{
protected $appends = array('imageAttribute');
protected $table = 'promotion_banner';
public function getPromotionImageAttribute() {
return (url('home/image/banner/'.$this->promotion_banner_id));
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'promotion_banner_id','promotion_link','about_promotion','promotion_active'
];
just improving, in case you need to pass data inside the query
$url = 'home/image/banner/';
$query = $query->map(function ($object) use ($url) {
// Add the new property
$object->promotion_image = URL::to( $url . $object->promotion_banner_id);
// Return the new object
return $object;
});
I've been struggling with this all evening, and I'm still not sure what my problem is.
I've used ->get() to actually execute the query, and I've tried by ->toArray() and ->jsonserialize() on the data and it didn't fix the problem.
In the end, the work-around I found was this:
$task = Tasks::where("user_id", $userId)->first()->toArray();
$task = json_decode(json_encode($task), true);
$task["foo"] = "bar";
Using json_encode and then json_decode on it again freed it up from whatever was keeping me from editing it.
That's a hacky work-around at best, but if anyone else just needs to push past this problem and get on with their work, this might solve the problem for you.

db query in codeigniter active record returing object

I'm trying to pull a column out of the database, simple enough right? I'm using codeigniter's active record.
My Model Function
public function getcolumn($field, $table, $kfield, $key)
{
$this->db->select($field);
$this->db->from($table);
$this->db->where($kfield, $key);
$query = $this->db->get();
$results = $query->result();
return $results;
}
My Controller has:
public function users()
{
$body['handle'] = $this->admin->getcolumn('handle', 'users', 'userid', $userid)
$this->load->view('template/header');
$this->load->view('admin/users', $body);
$this->load->view('template/footer');
}
now when I print_r that variable in my view I get "Array ( [0] => stdClass Object ( [handle] => Zanigade ) ) "
Since I'm trying to use this function as a global "grab and go" function without writing a ton of functions, why won't it just return the name? What am I doing wrong? I've been playing with the output for 3 hours and I know this is a stupid easy fix and I'm just missing the mark.
Any help will be appreciated.
Put it all together using the "chaining" capability like so
$results = this->db->get()->row()->$field;
We get() one row() which (should) contain a field named $field.
It seems you are returning the result instead of single row, try this
public function getcolumn($field, $table, $kfield, $key)
{
$this->db->select($field);
$this->db->from($table);
$this->db->where($kfield, $key);
$query = $this->db->get();
return $query->row()->$field;
}
For More Information, Check the codeigniter user guide
https://www.codeigniter.com/userguide3/database/examples.html

Call to a member function find() on a non-object()

Having started with CakePHP 3.0 I find docummentation very confusing as by following the code snippets I have genertaed the following code:
if($this->Auth->User('role') != 'Admin' ){
$query = $users->find('all')
->where(['Users.group_id' => $this->Auth->User('group_id')]);
$this->set('users', $this->paginate($query->all()));
}else{
$this->set('users', $this->paginate($this->Users));
}
Which runs perfectly fine if user is an admin, howver if he is not, then the code breaks on this line: $query = $users->find('all')
The following message is being provided:
Call to a member function find() on a non-object
The code is run in users controller.
Any help or guidance is much appreciated.
Try this instead:
if($this->Auth->User('role') != 'Admin' ){
$options = [
'conditions' => array(
"Users.group_id" => $this->Auth->User('group_id')
)];
$query = $users->find('all', $options);
$this->set('users', $this->paginate($query));
}else{
$this->set('users', $this->paginate($this->Users));
}
I think your issue is that you are essentially calling 'find' incorrectly.
$query = $users->find('all') ->$options
(not your exact code, but essentially what you have done, to help compare to my solution) should be
$query = $users->find('all', $options)
with $options declared above.
This is a much cleaner way (in my opinion at least) of managing find options, an can be reused if needed once they are set to a variable.

CakePHP 3.0 -> Between find condition

Is it possible to do a "BETWEEN ? AND ?" where condition LIKE in cakephp 2.5?
In cakephp 2.5 I write something like
'conditions' => ['start_date BETWEEN ? AND ?' => ['2014-01-01', '2014-12-32']]
how can I migrate that?
additionally I would write something like
'conditions' => [ '? BETWEEN start_date AND end_date'] => '2014-03-31']
Expressions
Between expression are supported out of the box, however they only support the first case without additional fiddling:
$Query = $Table
->find()
->where(function($exp) {
return $exp->between('start_date', '2014-01-01', '2014-12-32', 'date');
});
If you'd wanted to handle the second case via the between method, then you'd have to pass all values as expressions, which can easily go wrong, as they will not be subject to escaping/parameter binding in that case, you'd have to do that on your own (which is anything but recommended! See the security notes in the manual for PDO::quote()), something along the lines of:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$Query = $Table
->find()
->where(function(QueryExpression $exp, Query $query) {
return $exp->between(
$query->newExpr(
$query->connection()->driver()->quote(
'2014-03-31',
\PDO::PARAM_STR
)
),
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
});
That might feel a little inconvenient for such a basic SQL expression that is supported by all SQL dialects that CakePHP ships with, so you may have a reason here to use a raw SQL snippet with value bindig instead.
It should be noted however that expressions are often the better choice when it comes to for example cross dialect support, as they can be (more or less) easily transformed at compile time, see the implementations of SqlDialectTrait::_expressionTranslators(). Also expressions usually support automatic identifier quoting.
Value binding
Via manual value binding you can pretty much create anything you like. It should however be noted that whenever possible, you should use expressions instead, as they are easier to port, which happens out of the box for quite a few expressions already.
$Query = $Table
->find()
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', '2014-01-01', 'date')
->bind(':end', '2014-12-31', 'date');
That way the second case can also be solved very easily, like:
$Query = $Table
->find()
->where([
':date BETWEEN start_date AND end_date'
])
->bind(':date', '2014-03-31', 'date');
A mixture of both (safest and most compatible approach)
It's also possible to mix both, ie use an expression that makes use of custom bindings, something along the lines of this:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$Query = $Table
->find()
->where(function(QueryExpression $exp, Query $query) {
return $exp->between(
$query->newExpr(':date'),
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
})
->bind(':date', '2014-03-31', 'date');
That way you could handle the second case using possibly portable expressions, and don't have to worry about quoting/escaping input data and identifiers manually.
Regular comparison using array syntax
All that being said, in the end BETWEEN is just the same as using two separate simple conditions like this:
$Query = $Table
->find()
->where([
'start_date >=' => '2014-01-01',
'start_date <=' => '2014-12-32',
]);
$Query = $Table
->find()
->where([
'start_date >=' => '2014-03-31',
'end_date <=' => '2014-03-31',
]);
But don't be mad, if you read all the way down to here, at least you learned something about the ins and outs of the query builder.
See also
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions
API > \Cake\Database\Query::bind()
Currently there seems to be only two options. The core now supports this out of the box, the following is just kept for reference.
Value binding (via the database query builder)
For now the ORM query builder (Cake\ORM\Query), the one that is being retrived when invoking for example find() on a table object, doesn't support value binding
https://github.com/cakephp/cakephp/issues/4926
So, for being able to use bindings you'd have to use the underlying database query builder (Cake\Database\Query), which can for example be retrived via Connection::newQuery().
Here's an example:
$conn = ConnectionManager::get('default');
$Query = $conn->newQuery();
$Query
->select('*')
->from('table_name')
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', new \DateTime('2014-01-01'), 'date')
->bind(':end', new \DateTime('2014-12-31'), 'date');
debug($Query->execute()->fetchAll());
This would result in a query similar to this
SELECT
*
FROM
table_name
WHERE
start_date BETWEEN '2014-01-01' AND '2014-12-31'
A custom expression class
Another option would be a custom expression class that generates appropriate SQL snippets. Here's an example.
Column names should be wrapped into identifier expression objects in order to them be auto quoted (in case auto quoting is enabled), the key > value array syntax is for binding values, where the array key is the actual value, and the array value is the datatype.
Please note that it's not safe to directly pass user input for column names, as they are not being escaped! Use a whitelist or similar to make sure the column name is safe to use!
Field between values
use App\Database\Expression\BetweenComparison;
use Cake\Database\Expression\IdentifierExpression;
// ...
$between = new BetweenComparison(
new IdentifierExpression('created'),
['2014-01-01' => 'date'],
['2014-12-31' => 'date']
);
$TableName = TableRegistry::get('TableName');
$Query = $TableName
->find()
->where($between);
debug($Query->execute()->fetchAll());
This would generate a query similar to the one above.
Value between fields
use App\Database\Expression\BetweenComparison;
use Cake\Database\Expression\IdentifierExpression;
// ...
$between = new BetweenComparison(
['2014-03-31' => 'date'],
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
$TableName = TableRegistry::get('TableName');
$Query = $TableName
->find()
->where($between);
debug($Query->execute()->fetchAll());
This on the other hand would result in a query similar to this
SELECT
*
FROM
table_name
WHERE
'2014-03-31' BETWEEN start_date AND end_date
The expression class
namespace App\Database\Expression;
use Cake\Database\ExpressionInterface;
use Cake\Database\ValueBinder;
class BetweenComparison implements ExpressionInterface {
protected $_field;
protected $_valueA;
protected $_valueB;
public function __construct($field, $valueA, $valueB) {
$this->_field = $field;
$this->_valueA = $valueA;
$this->_valueB = $valueB;
}
public function sql(ValueBinder $generator) {
$field = $this->_compilePart($this->_field, $generator);
$valueA = $this->_compilePart($this->_valueA, $generator);
$valueB = $this->_compilePart($this->_valueB, $generator);
return sprintf('%s BETWEEN %s AND %s', $field, $valueA, $valueB);
}
public function traverse(callable $callable) {
$this->_traversePart($this->_field, $callable);
$this->_traversePart($this->_valueA, $callable);
$this->_traversePart($this->_valueB, $callable);
}
protected function _bindValue($value, $generator, $type) {
$placeholder = $generator->placeholder('c');
$generator->bind($placeholder, $value, $type);
return $placeholder;
}
protected function _compilePart($value, $generator) {
if ($value instanceof ExpressionInterface) {
return $value->sql($generator);
} else if(is_array($value)) {
return $this->_bindValue(key($value), $generator, current($value));
}
return $value;
}
protected function _traversePart($value, callable $callable) {
if ($value instanceof ExpressionInterface) {
$callable($value);
$value->traverse($callable);
}
}
}
You can use one of following 2 methods.
Method 1 :
$start_date = '2014-01-01 00:00:00';
$end_date = '2014-12-31 23:59:59';
$query = $this->Table->find('all')
->where(function ($exp, $q) use($start_date,$end_date) {
return $exp->between('start_date', $start_date, $end_date);
});
$result = $query->toArray();
Method 2:
$start_date = '2014-01-01 00:00:00';
$end_date = '2014-12-31 23:59:59';
$query = $this->Table->find('all')
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', new \DateTime($start_date), 'datetime')
->bind(':end', new \DateTime($end_date), 'datetime');
$result = $query->toArray();
I'm using it like this
$this->Table->find()->where(['data_inicio BETWEEN '.'\''.$data_inicio.'\''.' AND .'\''.$data_final.'\''.' ']);
Hello guys please use this query to get data on the basis of range of value
$query = $this->Leads->find('all',
array('conditions'=>array('postcode BETWEEN '.$postcodeFrom.' and'.$postcodeTo.''), 'recursive'=>-1));
debug($query);
print_r($query->toArray());

CakePHP, GET Parameters and routing

I am fairly new to cakephp but I have a question relating to urls and parameters. I would like to be able to have a url that looks like a standard url e.g:
http://www.mysite.com/controller/myaction?arg=value&arg2=val
I would like that url to map to an action in my controller as follows:
function myaction($arg = null, $arg2 = null)
{
// do work
}
I realize that cakephp has routing as described here, however, honestly this seems over engineered and results in a url string that is nonstandard.
In my current situation the url is being generated and invoked by an external (billing) system that knows nothing about cake and doesn't support the cake url format.
You can have your URL in any form. It's just CakePHP allows you to retrieve the variable passed through GET from the variable $this->params['url']
function myaction()
{
if(isset($this->params['url']['arg']))
$arg = $this->params['url']['arg'];
if(isset($this->params['url']['arg2']))
$arg2 = $this->params['url']['arg2'];
}
Solution in AppController for CakePHP 2.x
class AppController extends Controller {
....
/***
* Recupera los Named envias por URL
* si es null $key emtraga el array completo de named
*
* #param String $key
*
* #return mixed
*/
protected function getNamed($key=null){
// Is null..?
if(is_string($key)==true){
// get key in array
return Hash::get($this->request->param('named'), $key);
}else{
// all key in array
return $this->request->param('named');
}
}
...
}
I have a similar problem. Not because I have an external system, but because I don't like to put all parameters into the URL-path. In my example, I have some search queries that are assembled and passed to the controller. IMHO, these queries should be GET parameters and not part of the URL-path.
One advantage of using GET parameters is that the order of the given parameters is not important, in contrast to passing params via the URL path.
To solve this problem in a generic way, I'm replacing all method arguments with the value of the GET-param, if one with the same name is given:
class MyController extends AppController
{
function test($var1 = null, $var2 = "content2")
{
foreach (get_defined_vars() as $key => $value) {
if (isset($this->params['url'][$key])) {
$getvalue = $this->params['url'][$key];
$$key = $getvalue;
CakeLog::write("debug", "Setting:$key to $getvalue");
}
}
CakeLog::write("debug", print_r(get_defined_vars(), true));
}
}
Now I can access this controller method and pass parameters via GET like this:
http://myapp/mycontroller/test?var1=foo&var2=bar

Resources