I am trying to pass datetime variables into my exportcsv method to generate .csv file with data from indicated time period.
Both variables are associative arrays that look like this:
[
'beginning' => [
'year' => '2016',
'month' => '06',
'day' => '23',
'hour' => '11',
'minute' => '15'
],
'end' => [
'year' => '2016',
'month' => '06',
'day' => '29',
'hour' => '11',
'minute' => '15'
]
]
When I try to pass variables I get an error with this message (yep, I've got the same two warnings):
Warning (2): rawurlencode() expects parameter 1 to be string, array given [CORE\src\Routing\Route\Route.php, line 574]
Warning (2): rawurlencode() expects parameter 1 to be string, array given [CORE\src\Routing\Route\Route.php, line 574]
rawurlencode() is a basic PHP function and this is the line 574:
$pass = implode('/', array_map('rawurlencode', $pass));
It looks like some problem with URL rewriting, but frankly I don't know how to fix it. Any ideas?
exportcsv method in EventsController
public function exportcsv($beginning = null, $end = null)
{
if ($this->request->is('post')) {
$beginning = $this->request->data['Export']['beginning'];
$end = $this->request->data['Export']['end'];
return $this->redirect([$beginning, $end]);
}
if (!$beginning && !$end) {
return $this->render();
}
$this->response->download('export.csv');
$data = $this->Events->find('all')
->select([
'title',
'created',
'description',
'ended',
'working_hours',
'price',
'username' => 'Users.name',
'statusname' => 'Statuses.name',
'employeename' => 'Employees.name'
])
->leftJoinWith('Statuses')
->leftJoinWith('Users')
->leftJoinWith('Employees')
->where(["created BETWEEN " . $beginning . " AND " . $end])
->autoFields(true)
->toArray();
$_serialize = 'data';
$_delimiter = chr(9); //tab
$_extract = ['title', 'created', 'description', 'ended', 'working_hours', 'price', 'username', 'statusname', 'employeename'];
$this->set(compact('data', '_serialize','_delimiter', '_extract'));
$this->viewBuilder()->className('CsvView.Csv');
return;
}
exportcsv.ctp view:
<div class="events form large-6 medium-4 columns content">
<?= $this->Form->create('Export'); ?>
<?= $this->Form->input('beginning', array('type'=>'datetime', 'interval' => 15, 'label' => 'Beginning:')); ?>
<?= $this->Form->input('end', array('type'=>'datetime', 'interval' => 15, 'label' => 'End:')); ?>
<?= $this->Form->button(__('Add')) ?>
<?= $this->Form->end() ?>
</div>
You cannot pass arrays in a URL array, the router doesn't support that. Also you need to additionally pass Instead, convert your single values to proper datetime strings, you could easily do that via the DateTimeType class, something like
if ($this->request->is('post')) {
$beginning = $this->request->data('Export.beginning');
$end = $this->request->data('Export.end');
$type = \Cake\Database\Type::build('datetime');
$beginning = $type->marshal($beginning)->format('Y-m-d H:i:s');
$end = $type->marshal($end)->format('Y-m-d H:i:s');
return $this->redirect([
$beginning,
$end
]);
}
Also, as already mentioned in the comments, you need to fix your where() call, as currently it has an SQL injection vulnerability. The keys of key => value items, as well as value only items, are not going to be bound, but inserted into the query directly!
Cakes expression builder ships with methods to safely generate BETWEEN expressions:
->where(function(\Cake\Database\Expression\QueryExpression $exp) use ($beginning, $end) {
return $exp->between('Events.created', $beginning, $end);
});
See also
API > \Cake\Database\DateTimeType::marshal()
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions
CakePHP 3.0 -> Between find condition
your redirect is wrong
return $this->redirect([
'controller' => 'yourController',
'action' => 'yourAction',
$yourData]
);
see the Cookbook for more information on this topic
Related
I have an issue where I'm trying to get all descendants of an object and keep only those with a specific property.
I have these relations:
public function getChildren()
{
return $this->hasMany(self::class, 'parent_id', 'id');
}
public function allChildren()
{
return $this->getChildren()->with('allChildren');
}
And I get this type of array for example:
$array = [
0 => ['name' => 'aaa', 'type' => 0, 'parent' => null, 'children' => [
1 => ['name' => 'bbb', 'type' => 1, 'parent' => null, 'children' => []],
2 => ['name' => 'ccc', 'type' => 0, 'parent' => null, 'children' => [
3 => ['name' => 'ddd', 'type' => 1, 'parent' => 2, 'children' => []]
]]
]],
4 => ['name' => 'eee', 'type' => 0, 'parent' => null, 'children' => []]
];
For this example, I would like to remove all objects that are of type 1 and get a clean array without those only.
I don't really understand why it is possible to get all descendats of an object but not be able to pass conditions.
Thanks in advance.
A collection only solution would be something like this (place the custom macro in a Service Provider of your application):
Collection::macro('whereDeep', function ($column, $operator, $value, $nested) {
return $this->where($column, $operator, $value)->map(function ($x) use ($column, $operator, $value, $nested) {
return $x->put($nested, $x->get($nested)->whereDeep($column, $operator, $value, $nested));
});
});
Then where needed call:
$yourArray->whereDeep('type', '!=', 1, 'children');
On your example, the macro works like this:
Filter all the elements where: type != 1
(the outer array will beuntouched as both items has type => 0)
For each element of the current array:
Retrive the children property and apply the same filtering to this subarray starting with the first point of this instructions.
Replace the children property with the new children property just filtered.
Anyways, you should try to deep dive into why the relation filtering doesn't work. That solution would be more efficient if optimized correctly.
I found a great solution where there is no need of all this recursion or any of these relationship calls so I share it:
Using: "gazsp/baum"
// get your object with roots method
$contents = Content::roots()->get();
// and simply run through the object and get whatever you need
// thanks to getDescendantsAndSelf method
$myArray = [];
foreach($contents as $content) {
$myArray[] = $content->getDescendantsAndSelf()->where('type', '!=', 1)->toHierarchy();
}
return $myArray;
This works for me the same way as the other method above.
I want to filter an array over Hash::filter and use a callback function
static Hash::filter(array $data, $callback = array('Hash', 'filter'))
...You can also supply a custom $callback to filter the array elements...
(CakePHP Docs)
My question here is just... How?
Maybe there's a failure in my head with the translations, but i have the JavaScript filter function in mind, where you can filter over an array and give the filterfunction the actual element its iterating over atm. Then if it returns false it gets kicked out of the array.
maybe im just bad with php but.. could anybody help me with it, please? :)
my attempt atm is something like this
$bis_datum = '2017-01-01';
$res = Hash::filter($multidim_assoc_array, function($part_of_multidim_assoc_array){
return !strtotime($assoc_array['von_datum']) > strtotime($bis_datum);
});
i know there's something very wrong here, because it sais
array('Hash', 'filter')
in the docs and theres just an anonymous function here, but i dont get what the "Hash" and "filter" part means :S
$example = array(
'User' => array(
0 => array(
'name' => 'Bob',
'age' => 25
),
1 => array(
'name' => 'John',
'age' => 22
),
2 => array(
'name' => 'Jen',
'age' => 32
)
)
'School' => array(
'name' => 'Brainslaves High',
'adress' => 'Somestreet 42'
)
);
as an easy example.. how can i filter this array to kick out everyone whos age is below 25 ?
Thanks-a-lot!
Hash::filter won't help you for your example, you better work with array_filterdirectly
$res = array('User' => array_filter($example['User'], function($user) {
return $user['age'] > 25;
})) + array('School' => $example['School']);
I would like to make an associative array using PHP for loop to use in Yii2 map() method.
The array will look like in bellow format-
$listArray = [
['id' => '1', 'name' => 'Peter/5'],
['id' => '2', 'name' => 'John/7'],
['id' => '3', 'name' => 'Kamel/9'],
];
The id and name will be changed through each iteration of the loop. Here, the name will always hold customized value after some calculation inside the loop.
Finally, the list will be used in map() method like as following
$listData=ArrayHelper::map($listArray,'id','name');
I can use map() method directly after using the Active Record to find the list array and then use that in map() method. But it does not a give me way to use custom value for the name attribute.
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
$listData=ArrayHelper::map($listArray,'id','name');
How can achieve this? Direct source code example would be really great for me.
Thanks in advance.
I'm assuming you want to query an ActiveRecord for data then transfer the data into a simple array.
$listData = [];
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
foreach($listArray as $user){
$customName = $user->name . $this->someCalculation();
$listData[] = ["id" => $user->id, "name" => $customName];
}
Or you could use the ArrayHelper class like this:
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
$listData = ArrayHelper::toArray($listArray , [
'app\models\UserList' => [
'id',
'name' => function ($listArray ) {
return $listArray->word . strlen($listArray->word); // custom code here
},
],
]);
I think the preferred way of doing this by defining custom calculation rule in UserList model as:
public function getCustomRuleForUser(){
// Do what ever you want to do with your user name.
return $this->name.'Your custom rule for name';
}
And use as:
$userList = UserList::find()->all();
$listData=ArrayHelper::map($userList,'id','customRuleForUser');
Now, you have your custom rule for username list in $listData.
$model_userprofile = UserProfile::find()->where(['user_id' => Yii::$app->user->id])->one();
$model_userprofile1 = UserProfile::find()
->select('user_id')
->where(['group_id' => $model_userprofile->group_id])->all();
$listData = [];
foreach($model_userprofile1 as $user){
$id = $user->user_id;
$listData[] = ["id" => $id];
}
$dataProvider = new ActiveDataProvider
([
'query' => User::find()
->select('id,username,email')
->Where(['id' => $listData])
->orderBy(['id' => SORT_DESC]),
'pagination' => ['pagesize' => 15]]);
return $this->render('index',['dataProvider'=> $dataProvider]);
Sorry if this seems obvious but all the searches I am doing for this are returning complex answers and I have been struggling with this all day... I have been trying to create json data in PHP and really I want to send variables into the json data. I have not been able to do that so I followed a tutorial online and copied the code exactly yet i'm still not getting an output in my local host.. Please can somebody put me out of my misery...
<?php
$jsonData = new stdClass();
$people = array(
array(
'name' => 'Luci',
'age' => 25,
'sex' => 'female'
),
array(
'name' => 'John',
'age' => 27,
'sex' => 'male')
),
array(
'name' => 'Peter',
'age' => 22,)
'sex' => 'male'
)
);
$jsonData->source = "Program Knowledge";
$jsonData->published = date('Y-m-d H:s:i;');
$jsonData->status = true;
$jsonData->people = $people;
echo json_encode($jsonData);
?>
eventually I was going to try
$var = 123456;
$jsonData->codeid = $var
but I need to figure out just how to get it so work with data I have typed in.
Many thanks..!!
'sex' => 'male')
'age' => 22,)
Need to remove the parenthesis from these two lines, they're parsing errors
I have an array of data which contains associative array rows and I would like to sort them by price,date etc. This cannot be done via SQL as these values are not in a database - I simply have a large array with the following example data:
$data[0] = array(
'id' => '2',
'price' => '400.00',
'date' => '2012-05-21',
),
$data[1] = array(
'id' => '4',
'price' => '660.00',
'date' => '2012-02-21',
),
$data[2] = array(
'id' => '8',
'price' => '690.00',
'date' => '2012-01-21',
)
etc..................
How can I sort this variable based on a select box such as sort by price ASC/DESC and date ASC/DESC
Sorry if this is simple - I am just so used to doing it via SQL that my mind has gone blank in this case.
I think you may modify this function:
http://php.net/manual/en/function.sort.php#104464
You should use usort and define a function which sorts based on the key you want.
Check out http://www.php.net/manual/en/function.usort.php examples 2 and 4.
Below sample code will sort it by id.
$capitals = array(
array(
'id' => '2',
'price' => '400.00',
'date' => '2012-05-21',
),
array(
'id' => '1',
'price' => '660.00',
'date' => '2012-02-21',
),
array(
'id' => '0',
'price' => '690.00',
'date' => '2012-01-21',
)
);
function cmp($a, $b)
{
return strcmp($a["id"], $b["id"]);
}
usort($capitals, "cmp");
print_r($capitals);
Use usort:
function sortBySubKey(&$array, $key)
{
return usort($array, create_function('$a,$b', 'if ($a["'.$key.'"] == $b["'.$key.'"]) return 0; return ($a["'.$key.'"] < $b["'.$key.'"]) ? -1 : 1;'));
}
You should make sure that your array holds valid values in the sense of this arithmetical comparision (<), eg. you should probably pass date as a unix timestamp for this, price as a float and so on...