CakePHP query array - php

I am running this query using CakePHP:
$total = $this->Lapse->query("select sum(unix_timestamp(stop) - unix_timestamp(start)) from lapses where id = ".$lastId."");
And i get back this array structure:
Array
(
[0] => Array
(
[0] => Array
(
[sum(unix_timestamp(stop) - unix_timestamp(start))] => 1
)
)
)
So my variable holds this: $updateVal = $total[0][0][0];
Which isn't the prettiest, is there a way i can simplify this OTT array?

Have you tried the find() method passing a custom fields option?:
$this->Lapse->find('all', array(
'fields' => array('sum(unix_timestamp(stop) - unix_timestamp(start)) as elapsed_time'),
'conditions' => array('Lapse.id' => $lastId),
));
The returned array is prettier than the one you're getting, although it's not prettier than elapsed_time being an actual model property.
Another solution would be to set elapsed_time as a virtual field within the model:
class Lapse extends AppModel {
...
public $virtualFields = array(
'elapsed_time' => 'sum(unix_timestamp(Lapse.stop) - unix_timestamp(Lapse.start)',
);
...
}
Then elapsed_time acts as a model property and would be returned as $updateVal['Lapse']['elapsed_time'] in every find() call.

Related

Yii 2.0 $request->post() issues

In my controller I have the following lines
$request = Yii::$app->request;
print_r($request->post());
echo "version_no is ".$request->post('version_no',-1);
The output is given below
Array
(
[_csrf] => WnB6REZ6cTAQHD0gAkoQaSsXVxB1Kh5CbAYPDS0wOGodSRANKBImVw==
[CreateCourseModel] => Array
(
[course_name] => test
[course_description] => kjhjk
[course_featured_image] =>
[course_type] => 1
[course_price] => 100
[is_version] => 1
[parent_course] => test
[version_no] => 1
[parent_course_id] => 3
[course_tags] => sdsdf
)
)
version_no is -1
So here the return value of post() contains the version_no.But when it is called as $request->post("version_no"), it is not returning anything (or $request->post("version_no",-1) returns the default value -1).
As per Yii 2.0 docs, the syntax is correct and should return the value of post parameter.
But why is it failing in my case.The post array has the parameter in it.But the function is not returning when called for an individual parameter value.
your parameters are in $_POST['CreateCourseModel']['version_no'] etc. with $request->post('version_no',-1) you trying to get $_POST['version_no'] which is not defined so it returns you -1. So to get version_no use
$data = $request->post('CreateCourseModel');
print_r($data['version_no']);
You can access nested $_POST array elements using dot notation:
\Yii::$app->request->post('CreateCourseModel.version_no', -1);
Model properties are grouped like that for massive assignment that is done via $model->load(Yii::$app->request->post()).
Depending on your needs maybe it's better use default value validator like that:
['version_no', 'default', 'value' => -1],

What multi dimensional array needed to store 3 levels of information?

I'm working on a PHP script to hold a lot of information.
Lets try to explain our situation!
I have actually 33 different stations.
For each of that 33 stations I have 5 different categories.
And for each of that 33 stations with each 5 different categories i have 37 different values per category.
Do I need an 2d of 3d array for store this information in it ?
Thanks you!
Something like this will work, just add more data as needed:
$station_array =
array(
'station1' => array(
'cat1' => array ('val1','val2','val3'),
'cat2' => array ('val1','val2','val3'),
'cat3' => array ('val1','val2','val3')
),
'station2' => array (
'cat1' => array ('val1','val2','val3'),
'cat2' => array ('val1','val2','val3'),
'cat3' => array ('val1','val2','val3')
),
'station3' => array (
'cat1' => array ('val1','val2','val3'),
'cat2' => array ('val1','val2','val3'),
'cat3' => array ('val1','val2','val3')
)
);
Sounds like a job for a relational database!
But you're correct in your initial assumption. You will need a 3-dimensional array to hold your information because your data has 3 tiers: the stations, the categories, and the values.
A php array will be fine for this
$MyArray = array('Station1' => array('Category1' =>
array('Value1'=> 1000,'Value2'=> 1001),
'Category2' => array('Value1' => 2332)), etc...
'Station2' => array('Category1' =>
array('Value1'=> 1000,'Value2'=> 1001),
'Category2' => array('Value1' => 2332)), etc
etc
);
Once you pass more than two dimensions in an associative array, it's good to start considering using objects to store your information. Objects make it a lot easier to understand how things are organized, they can enforce validation restrictions on your data (make sure it's in the form it should be), and you can call functions on the data to manipulate it (instead of having random external functions manipulating your entire array). An example would be:
class CategoryValue {
var $val; // your value
function __construct($val) {
$this->val = $val;
}
}
class Category {
var $values = array(); // an array of CategoryValue objects
function addValue(CategoryValue $val) {
$this->values[] = $val;
}
}
class Station {
var $categories = array(); // an array of Category objects
function addCategory(Category $category) {
$this->categories[] = $category;
}
}
well, all depends on how you want to acheive, if you dont need to loop through the values, but you just want to store data and alway know whay you want to get, you could use hashes for that, the table would look like:
$data = array(
md5('StationX'.'CategoryY'.'PropertyZ') => 'ValueU',
md5('StationA'.'CategoryB'.'PropertyC') => 'ValueQ'
);
This way you can get the data right away and dont have to bother to check if you initialised CategoryB array for StationA when you want to add value for PropertyZ
php stores associative arrays as hastables technically
... thats all if you really insist on not using databases ;)

How is it possible to correctly nest custom fields in a CakePHP find query?

we're often dealing with a code that looks like the following:
return $this->find(
'all', [
'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as count'],
'group' => ['Tag.tag'],
'order' => ['count' => 'DESC']
]);
This query leads us to the following output:
[0] => Array
(
[Tag] => Array
(
[tag] => walls.io
)
[0] => Array
(
[count] => 15
)
)
As you can see, the query returns the results in a "somehow wrong" nesting. The "count" field is unfortunately put into a pseudo [0]-array.
IIRC, CakePHP uses internally a syntax like Tag__field for correctly nesting virtual fields.
When changing the code to the Model__-syntax, the problem stays the same:
return $this->find(
'all', [
'fields' => ['DISTINCT Tag.tag', 'COUNT(Tag.tag) as Tag__count'],
'group' => ['Tag.tag'],
'order' => ['COUNT(Tag.tag)' => 'DESC']
]);
Output:
[0] => Array
(
[Tag] => Array
(
[tag] => walls.io
)
[0] => Array
(
[Tag__count] => 15
)
)
Workaround 1: array_map
CakePHP pros: Is there a better/more elegant solution than manually mapping the array after the select statement?
$tags = array_map(function($tag) {
$tag['Tag']['count'] = $tag[0]['count'];
unset($tag[0]);
return $tag;
}, $tags);
Workaround 2: virtual field
As described above, the usage of a virtual field might solve this problem:
$this->virtualFields = ['count' => 'COUNT(Tag.Tag)'];
return $this->find(
'all', [
'group' => ['Tag.tag'],
'order' => [$this->getVirtualField('count') => 'DESC']
]);
Unfortunately, with this solution, it's not possible to specify ANY fields at all. only by completely leaving the "fields"-key, the nesting of the array works as expected. when selecting $fields = ['Tag.tag', $this->getVirtualField('count')] the nesting is wrong again.
CakePHP pros: Do you know a method, where the nesting is done right, even if you specify your own fields?
Looking at the CakePHP code, such a method does not exist.
Have a look at the file lib/Cake/Model/Datasource/Database/Mysql.php.
Find the method called: Mysql::resultSet( $results ); (around line 240).
That method maps the result to an array. To determine if a column is part of a table or not it uses PDOStatement::getColumnMeta(). For your "virtual column" that method will return an empty table and so the CakePHP code will put it separately, see the else branch
$this->map[$index++] = array(0, $column['name'], $type);
In order to avoid that else branch you would have to use Virtual fields, but then you run into the other problems that you have noticed.
So you are left with the array_map solution or you could try to overload that Mysql class and add your custom logic at how to identify where a column fits.

Use returned data from array

I get some data from a table
Data is returned into an array like this
Array ( [id_widget] => 11 [id_user] => 7 [active] => 1 )
Then I am trying to use this "id_widget" and "entryemail" to insert them into another table.
"newentry" comes from an input, but I don't know how to post the "id_widget"
This is my model function
public function addentry($data) {
$this->db->insert('entries', array(
'id_widget' => $data['id_widget'],
'entryemail' => $data['entryemail']
));
}
This is my controller function:
public function entercontest() {
$entry = array(
'id_widget' => $this->widget[0]['id_widget'],
'entryemail' => $_POST['entryemail']
);
$this->model->addentry($entry);
}
It works to insert "entryemail" if I comment id_widget line everywhere.
The error doesn't occur when getting the value from the array $data['id_widget']. The error occurs in the entercontent function because you're populating the array with an undefined value because $this->widget is undefined.
Make sure $this->widget is defined and has the data before using it.

symfony propel : wrongly populated object with criteria addJoin

This is my first question here, so please try to be patient with me :)
I've stumbled upon a weird behavior populating an object.
I started to convert the objectQuery::create()-> ... ->find() methods used in my project to $c = new Criteria(), $c-> ... objectPeer::doSelect($c) since I've been told Queries shouldn't be used when criteria can be.
I have a function, that returns all the prices of items from the shop. Or at least did. The thing that I cannot figure out is this:
the old code:
static public function shopGetPrices($id){
$prices = itemPriceQuery::create()->
addJoin(itemPricePeer::ITEM_ID, itemPeer::ID, Criteria::LEFT_JOIN)->
addJoin(itemPeer::CATEGORY_ID, categoryPeer::ID, Criteria::LEFT_JOIN)->
addJoin(categoryPeer::SHOP_ID, shopPeer::ID, Criteria::LEFT_JOIN)->
add(shopPeer::ID, $id)->find();
return $prices;
}
returns correctly populated PropelObjectCollection object, through which i can go with foreach, and get/set the itemPrice objects and attributes i need.
now, the new code:
static public function shopGetPrices($id){
$c = new Criteria();
$c->addJoin(itemPricePeer::ITEM_ID, itemPeer::ID, Criteria::LEFT_JOIN)->
addJoin(itemPeer::CATEGORY_ID, categoryPeer::ID, Criteria::LEFT_JOIN)->
addJoin(categoryPeer::SHOP_ID, shopPeer::ID, Criteria::LEFT_JOIN)->
add(shopPeer::ID, $id);
return self::DoSelect($c);
}
returns an array of itemPrice objects, but they are populated with item values related to itemPrice objects through join. that means : when I call print_r(self::DoSelect($c)); it prints
Array
(
[0] => ItemPrice Object
(
[startCopy:protected] =>
[id:protected] => 47 <- id of joined item
[item_id:protected] => 9 <-foreign key to category object of joined item
[price:protected] => 0
[unit:protected] => Axe <- name of item, not unit (unit is like 'golden', 'iron', 'wood' or whatever )
[active:protected] =>
[collItemsOrder:protected] =>
[collItemsOrderPartial:protected] =>
[alreadyInSave:protected] =>
[alreadyInValidation:protected] =>
[polozkyObjednavkasScheduledForDeletion:protected] =>
[prisadyPolozkyObjednavkasScheduledForDeletion:protected] =>
[validationFailures:protected] => Array()
[_new:protected] =>
[_deleted:protected] =>
[modifiedColumns:protected] => Array()
[virtualColumns:protected] => Array()
)
[1] => ItemPrice Object
(
...and so on.
There is probably some crucial difference between criteria and query object, that I'm missing. I searched on Google, StackOverflow, and who knows where, but I didn't find anything resembling a solution to this.
This guy/gal had a vaguely similar problem, but I didn't use addSelectColumn with my criteria, so it's been another dead end for me.
Can anyone please point me in the right direction?
I found the problem. It was that I had overriden method do select in itemPricePeer class
public static function doSelect(Criteria $criteria, PropelPDO $con = null){
$critcopy = clone $criteria;
$critcopy->add(self::ACTIVE, 1);
return self::populateObjects(itemPeer::doSelectStmt($critcopy, $con));
}
I switched self/itemPricePeer with itemPeer in populateObjects arguments. silly me :-/ Thanks for your responses anyway j0k.

Categories