db query in codeigniter active record returing object - database

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

Related

How to save data in the database using codeigniter?

public function registration_insert($data) {
//$this->db->trans_start();
//echo "<pre>";print_r($_POST);die;
// Query to check whether username already exist or not
$condition = "user_name =" . "'" . $data['user_name'] . "'";
$this->db->select('*');
$this->db->from('user_login');
$this->db->where($condition);
$this->db->limit(1);
$query = $this->db->get();
// Query to insert data in database
$this->db->insert('user_login', $data);
if ($this->db->affected_rows() > 0) {
return true;
}
This is my program. It is not executing this code. I want to store the data in the database. Explicitly, with print_r(), it is posting the data but it is not storing it in the database and it is showing error.
First of all, i want to check your $data variable , if $data is not an object that have the sames attribute name like your database table column that will give you a problem.
I mean, for exemple if your user_login table have tow column (id , user_name), you should have in the $data object the same name of attributes
and to verify if your query work correctly just your code will be like this :
$q = $this->db->insert('user_login', $data);
if ($q) {
return $this->db->insert_id();
} else {
return false;
}

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.

Cakephp How to set find() to return blank array instead of empty array when no result matched

By default , cakephp would return empty array on find() when nothing founded.
but how to set it to show as blank array.
For example:
$customer = $this->Transaction->Customer->find(--conditions to return 0 result.--)
I want it to show as blank array like this.
array('Customer' => array('customer_id'=>null, 'name'=>null, 'lastname'=>null))
not just empty one like
array() or null
because I always got error shown in view that $customer['Customer']['name'] is undefined index. and I don't like to use isset() or is_null() to check before every time.
Use the afterFind callback method in your model. Something like this:
public function afterFind($results, $primary = false) {
if (empty($results)) {
$results = array('Customer' => array('customer_id'=>null, 'name'=>null, 'lastname'=>null))
}
return $results;
}
http://book.cakephp.org/2.0/en/models/callback-methods.html
If you really want/need to do this, you can use something like:
$default = array('Customer' => array('customer_id' => null, 'name'=>null, 'lastname' => null));
$customer = $this->Transaction->Customer->find(...)
$customer = array_merge($default, $customer);
This way, if the result is empty, it will use your default values.
However, this is not a good practice, because you might end up displaying "Welcome, NULL", in the page. You should use if (!empty($customer)) ... in your view.
Also, in this example, are you using find->('first') ?

Custom component won't return value

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.

Yii - How to get a values array from an Active Record

Using Yii, how can I get an array from an Active Record.
Say something like this:
array('foo', 'bar', 'lala')
From something like this:
MyTable::model()->findall()
If i understand you correctly:
$users = User::model()->findAll();
$usersArr = CHtml::listData( $users, 'id' , 'name');
print_r( $usersArr );
It will give you array id => name
Array {
2 => 'someone',
20 => 'kitty',
102 => 'Marian',
// ...
}
For yii2 , use:
yii\helpers\ArrayHelper::map(MyModel::find()->all(), 'id', 'name'));
or
yii\helpers\ArrayHelper::getColumn(MyModel::find()->all(), 'name'));
ActiveRecord class has an attribute called attributes. You can find its description here: http://www.yiiframework.com/doc/api/1.1/CActiveRecord#attributes-detail.
In order to get all attributes in an array, use this: $var = $model->attributes;
You could also do something like
$countries = Country::model()->findAll();
array_values(CHtml::listData($countries, 'country_id', 'country_name'));
which returns an array of all country names, or
array_keys(CHtml::listData($countries, 'country_id', 'country_name'));
which returns an array of all country ids.
How about:
Yii::app()->db->createCommand()
->setFetchMode(PDO::FETCH_COLUMN,0)
->select("mycolumn")
->from(MyModel::model()->tableSchema->name)
->queryAll();
The result would be:
array('foo', 'bar', 'lala')
Use the Yii2 ArrayHelper by including to your controller this will convert a model data to an associated array
use yii\helpers\ArrayHelper;
$post = ArrayHelper::toArray(ClientProfilesForm::findOne(['id' => 1]));
//or use it directly by
$post = yii\helpers\ArrayHelper::toArray(ClientProfilesForm::findOne(['id' => 1]));
Don't use ActiveRecord. Use CDBCommand->queryColumn()
Use Chtml to this is a Ugly Hack! Apply this solution is the better way to this that I found:
public function queryAll($condition = '', $params = array())
{
$criteria = $this->getCommandBuilder()->createCriteria($condition, $params);
$this->applyScopes($criteria);
$command = $this->getCommandBuilder()->createFindCommand($this->getTableSchema(), $criteria);
$results = $command->queryAll();
return $results;
}
You can add this code to an ActiveRecord class, e.g.:
class ActiveRecord extends CActiveRecord {
//...
}
And, use this way:
return $model->queryAll($criteria);
You can read more about in this link.
if you are using Yii1.1 and you need to get ALL data from AR as array you need to care about that it self. Yii1.1 AR doesn't have this feature out of the box
In Yii2 AR has asArray() method, it's very helpful
I hope my answer helps someone
Model::find()->select('id')->column();
Will return array of IDs.

Resources