using same array in different functions - arrays

Here's the situation: I have 2 different functions and one view. I need to send data from function 1 to the view (2 arrays), and from that view i need to send data to function 2 (1 array).
Sending data from function 1 to the view is an easy job, but i don't know how to do it with function 2 because the information i would like to send to it has a function 1's array plus other new data the users entry.
I know there's no chance to send an array through URL, but i'm out of ideas.
Which is the best option for passing the data?
i send to the view this data:
admin: (part of the function 1)
//last part of the code
$this->data['conditions'] = $conditions;
$this->data['notselectedconditions'] = $notselectedconditions;
$this->parser->parse('admin/tools/showReport.tpl',$this->data);
In the view i use the information on those arrays, and user can put some new entry.
view:
<dt>Tipo de Usuario<dt>
<dd>Pre Registrado</dd>
reloadConditions is function 2, the one that needs what function 1 provides plus the selection of the user in order to keep filtering the results.
The information i need to have available on function 2 is: array 'conditions' and users new entry

After a long discussion and some clarifications in chat, here is the solution I came up with:
<?php
function addQueryParameters($url, $params) {
$paramsStr = http_build_query($params);
$fragment = parse_url($url, PHP_URL_FRAGMENT);
$query = parse_url($url, PHP_URL_QUERY);
$interUrl = '';
if ($query === NULL) {
$interUrl = '?';
}
if ($fragment !== NULL) {
$interUrl = '&';
}
$interUrl .= $paramsStr;
if ($fragment !== NULL) {
$pos = strpos($url, '#' . $fragment);
$url = substr($url, 0, $pos) . $interUrl . substr($url, $pos);
}
return $url;
}
function linkifyFilterConditions($url, $conditions) {
return addQueryParameters($url, array('conditions' => $conditions));
}
// Tests
// TODO: replace by unit tests
var_dump(linkifyFilterConditions('http://example.com/blub', [1,2,3]));
var_dump(linkifyFilterConditions('http://example.com/blub#a', [1,2,3]));
var_dump(linkifyFilterConditions('http://example.com/blub?a=b#a', [1,2,3]));
Usage (in OP's views):
$href = 'yourscript?conditions[]=a';
$href = linkifyFilterConditions($href, $conditions);
echo '<a href="' . $href . '">Test</>';

How about puting you arrays in $_SESSION?
see here http://www.phpriot.com/articles/intro-php-sessions/7

Related

Symfony - saving array to database

I wrote a function where I get array of marks that i need to post to my database..
My function stores it in a filed row like:
And I need to pull just one per column individually like:
Here is my api call..
public function generate(Map $seatMap)
{
$layout = $seatMap->getSeatLayout();
$seats = [];
$layoutArray = json_decode($layout, true);
$columns = range('A', 'Z');
foreach($layoutArray as $index => $result)
{
$columnLetter = $columns[$index];
$letters = str_split($result);
$letterIndex = 1;
foreach($letters as $letterIndex => $letter) {
switch($letter) {
case 'e':
$seats[] = $columnLetter . $letterIndex;
$letterIndex++;
}
}
}
foreach($seats as $seat => $result) {
$result = new Seat();
$result->setName(json_encode($seats));
$this->em->persist($result);
$this->em->flush();
}
}
Any suggestions?
I think that problem is in the part where I need to store it to database..
If I understand you correctly, your issue is here:
foreach($seats as $seat => $result) {
$result = new Seat();
$result->setName(json_encode($seats));
$this->em->persist($result);
$this->em->flush();
}
}
You're indeed creating new Seat instance for every seat, but in this line:
$result->setName(json_encode($seats));
you still assign all (encoded) seats to every instance of Seat. What you want is to assign only the seat from current loop iteration, which is represented by $result variable.
So try with:
$result->setName($result);
You do not need json_encode here too.
If your array is like you say it it then try this
foreach($seats as $seat) {
$result = new Seat();
$result->setName($seat);
$this->em->persist($result);
$this->em->flush();
}

How do you filter Joomla 3 articles by article id

I'm trying to create a Joomla module that displays articles based on categories and tags.
I've taken code for selecting tagged articles from https://github.com/lasinducharith/joomla-tags-selected) and introduced it into a copy of mod_articles_news:
public static function getList(&$params)
{
$app = JFactory::getApplication();
$db = JFactory::getDbo();
// Code base on https://github.com/lasinducharith/joomla-tags-selected to fetch ids of tagged articles
$tagsHelper = new JHelperTags;
$tagIds = $params->get('tagid', array());
$tagIds = implode(',', $tagIds);
echo '<pre>search for tags[' . $tagIds . ']';
$query=$tagsHelper->getTagItemsQuery($tagIds, $typesr = null, $includeChildren = false, $orderByOption = 'c.core_title', $orderDir = 'ASC',$anyOrAll = true, $languageFilter = 'all', $stateFilter = '0,1');
$db->setQuery($query, 0, $maximum);
$results = $db->loadObjectList();
$article_ids=array();
foreach ($results as $result){
$article_ids[]=$result->content_item_id;
}
echo ' yields articles[' . implode(',', $article_ids ) . ']</pre>';
// Get an instance of the generic articles model
$model = JModelLegacy::getInstance('Articles', 'ContentModel', array('ignore_request' => true));
// Set application parameters in model
$appParams = JFactory::getApplication()->getParams();
$model->setState('params', $appParams);
// Set the filters based on the module params
$model->setState('list.start', 0);
$model->setState('list.limit', (int) $params->get('count', 15));
$model->setState('filter.published', 1);
$model->setState('list.select', 'a.fulltext, a.id, a.title, a.alias, a.introtext, a.state, a.catid, a.created, a.created_by, a.created_by_alias,' .
' a.modified, a.modified_by, a.publish_up, a.publish_down, a.images, a.urls, a.attribs, a.metadata, a.metakey, a.metadesc, a.access,' .
' a.hits, a.featured' );
// Access filter
$access = !JComponentHelper::getParams('com_content')->get('show_noauth');
$authorised = JAccess::getAuthorisedViewLevels(JFactory::getUser()->get('id'));
$model->setState('filter.access', $access);
// Category filter
$model->setState('filter.category_id', $params->get('catid', array()));
// Article filter
$model->setState('filter.id', $article_ids);
// Filter by language
$model->setState('filter.language', $app->getLanguageFilter());
// Set ordering
$ordering = $params->get('ordering', 'a.publish_up');
$model->setState('list.ordering', $ordering);
if (trim($ordering) == 'rand()')
{
$model->setState('list.direction', '');
}
else
{
$direction = $params->get('direction', 1) ? 'DESC' : 'ASC';
$model->setState('list.direction', $direction);
}
// Retrieve Content
$items = $model->getItems();
$newitems=array();
foreach ($items as &$item)
{
echo '<pre>fetched article[' . $item->id .'] which is ';
if ( !in_array($item->id, $article_ids )){
echo 'not tagged';
} else{
echo 'tagged';
}
echo '</pre>';
...
}
return $newitems;
}
The debug statements give me:
search for tags[2] yields articles[40,44,45]
fetched article[45] which is tagged
fetched article[44] which is tagged
fetched article[43] which is not tagged
fetched article[42] which is not tagged
fetched article[41] which is not tagged
fetched article[40] which is tagged
fetched article[39] which is not tagged
fetched article[38] which is not tagged
So the articles have not been filtered by id. I'd be very grateful for any advice.
Thanks
Found the problem, the filter should be article_id:
// Article filter
$model->setState('filter.article_id', $article_ids);
Now it selects articles based on tags and categories

How can I convert validation error field names to input names in CakePHP?

I have a CakePHP (latest version) web app with forms and validation all working properly using traditional postback, but now I'm switching some of the forms to submit via ajax. When there are validation errors, I would like to get them back on the client as JSON formatted like so:
{
"success":false,
"errors":{
"data[User][username]":["This is not a valid e-mail address"],
"data[User][password]":["You must choose a password"]
}}
The keys for the errors array need to correspond to the name attribute on the form fields. We have some prebuilt client script that is expecting JSON formatted in this way. The good news is that this is very close to what the validationErrors object looks like in CakePHP. So I'm currently doing this in my controller:
if ($this->User->save($this->request->data)) {
} else {
if ($this->request->is('ajax')) {
$this->autoRender = $this->layout = false;
$response['success'] = false;
$response['errors'] = $this->User->validationErrors;
echo json_encode($response);
exit(0);
}
}
However, this is what the JSON response looks like:
{
"success":false,
"errors":{
"username":["This is not a valid e-mail address"],
"password":["You must choose a password"]
}}
Note that the errors keys have just the basic database table field names in them. They are not converted into data[User][username] format, which the FormHelper usually takes care of.
Is there some easy way to adjust the array before I return it? I don't want to simply loop through and prepend "data[User]" because that is not robust enough. I'd like some code I can put in one place and call from various controllers for various models. What does FormHelper use to come up with the input name attributes? Can I tap into that? Should I somehow use a JSON view?
That's because that's the way the $validationErrors array is formatted. To obtain the output you want you will have to loop through, there's no way around it.
foreach ($this->User->validationErrors as $field => $error) {
$this->User->validationErrors["data[User][$field]"] = $error;
unset($this->User->validationErrors[$field]);
}
I would suggest instead passing all errors to json_encode(). $this->validationErrors is a combined list of all model validation errors for that request available on the view (compiled after render). You should move your display logic (echoing json) into your view, and loop through it there.
in the view
$errors = array();
foreach ($this->validationErrors as $model => $modelErrors) {
foreach ($modelErrors as $field => $error) {
$errors["data[$model][$field]"] = $error;
}
}
$response['errors'] = $errors;
echo json_encode($response);
This would output something like this:
{
"success":false,
"errors": [
"data[User][username]": "This is not a valid e-mail address",
"data[User][password]": "This is not a valid password",
"data[Profile][name]": "Please fill in the field"
]
}
I have created a small recursive function to create validation error as a string with column name so that can be passed as json object.
/**
* prepare erorr message to be displayed from js
*
* #param array $errors validation error array
* #param stringn $message refernce variable
*
* #return void
*/
public function parseValidationErrors($errors, &$message)
{
foreach ($errors as $columnName => $error) {
$message .= "<strong>$columnName:</strong> ";
foreach ($error as $i => $msg) {
if (is_array($msg)) {
$this->_parseValidationErrors($msg, $message);
} else {
$message .= str_replace("This field", "", $msg . " ");
isset($error[$i + 1]) ? $message .= " and " : $message;
}
}
}
}
and controller code goes like this.
if (!$this->YourModel->saveAll($modelObject)) {
$errors = $this->YourModel->validationErrors;
$message = '';
$this->parseValidationErrors($errors, $message);
$response = array('status' => 'error', 'message' => $message);
}
$response['errors']['User'] = $this->User->validationErrors;

How do I use fixed fields in CakeDC's csvUpload behavior in Util plugin

I am using the csvUpload behavior of the Utils plugin by CakeDC, on a CakePHP 2.2.1 install.
I have it working great it's processing a rather large csv successfully. However there are two fields in my table / Model that would be considered fixed, as they are based on ID's from from associated models that are not consistent. So I need to get these fixed values via variables which is easy enough.
So my question is, how do I use the fixed fields aspect of csvUpload? I have tried that following and many little variation, which obviously didn't work.
public function upload_csv($Id = null) {
$unique_add = 69;
if ( $this->request->is('POST') ) {
$records_count = $this->Model->find( 'count' );
try {
$fixed = array('Model' => array('random_id' => $Id, 'unique_add' => $unique_add));
$this->Model->importCSV($this->request->data['Model']['CsvFile']['tmp_name'], $fixed);
} catch (Exception $e) {
$import_errors = $this->Model->getImportErrors();
$this->set( 'import_errors', $import_errors );
$this->Session->setFlash( __('Error Importing') . ' ' . $this->request->data['Model']['CsvFile']['name'] . ', ' . __('column name mismatch.') );
$this->redirect( array('action'=>'import') );
}
$new_records_count = $this->Model->find( 'count' ) - $records_count;
$this->Session->setFlash(__('Successfully imported') . ' ' . $new_records_count . ' records from ' . $this->request->data['Model']['CsvFile']['name'] );
$this->redirect(array('plugin'=>'usermgmt', 'controller'=>'users', 'action'=>'dashboard'));
}
}
Any help would be greatly appreciated as I have only found 1 post concerning this behavior when I searching...
I made my custom method to achieve the same task. Define the following method in app\Plugin\Utils\Model\Behavior
public function getCSVData(Model &$Model, $file, $fixed = array())
{
$settings = array(
'delimiter' => ',',
'enclosure' => '"',
'hasHeader' => true
);
$this->setup($Model, $settings);
$handle = new SplFileObject($file, 'rb');
$header = $this->_getHeader($Model, $handle);
$db = $Model->getDataSource();
$db->begin($Model);
$saved = array();
$data = array();
$i = 0;
while (($row = $this->_getCSVLine($Model, $handle)) !== false)
{
foreach ($header as $k => $col)
{
// get the data field from Model.field
$col = str_replace('.', '-', trim($col));
if (strpos($col, '.') !== false)
{
list($model,$field) = explode('.', $col);
$data[$i][$model][$field] = (isset($row[$k])) ? $row[$k] : '';
}
else
{
$col = str_replace(' ','_', $col);
$data[$i][$Model->alias][$col] = (isset($row[$k])) ? $row[$k] : '';
}
}
$is_valid_row = false;
foreach($data[$i][$Model->alias] as $col => $value )
{
if(!empty($data[$i][$Model->alias][$col]))
{
$is_valid_row = true;
}
}
if($is_valid_row == true)
{
$i++;
$data = Set::merge($data, $fixed);
}
else
{
unset($data[$i]);
}
}
return $data;
}
And you can use it using:
$csv_data = $this->Model->getCSVData($this->request->data['Model']['CsvFile']['tmp_name'], $fixed);
Here $csv_data will contain an array of all of those records from the csv file which are not empty and with the fixed field in each record index.
So as I was telling Arun, I answered my own question and figured it out. I was looking to broad instead of really examining what was in front of me. I started running some debugging and figured it out.
First of all, $unique_add = 69 is seen as an int, duh. In order for it to be added to the csv it need to viewed as a string. So it simply becomes, $unique_add = '69'.
I couldn't enter the value of $Id directly into the fixed array. So I just had to perform a simple find to get the value I needed.
$needed_id = $this->Model->find('first', array(
'condition'=>array('Model.id'=>$Id)
)
);
$random_id = $needed_id['Model']['id'];
Hopefully this won't be needed to help anyone because hopefully no one else will make this silly mistake. But one plus... Now there's actually more than one post on the internet documenting the use of fixed fields in the CakeDC Utils plugin.

Cakephp, i18n, Retrieve translation records for associated models

Quoting from the cakephp Book (ver 1.3):
Note that only fields of the model you are directly doing find on will be translated. Models attached via associations won't be translated because triggering callbacks on associated models is currently not supported.
Has anyone come up with a solution for this?
If not could you give me some pointers concerning the following simple scenario.
I have 2 models:
Project, Category.
Project HABTM Category
I have properly set up i18n table and I have a few entries in the db, all translated. When I retrieve a project it does retrieve the translation but not the translated category because as it says in the cakephp book models attached via associations won't be translated.
I have another workaround; I don't know if it is any better or worse performance- or style-wise, only that it suits the "fat models, skinny controllers" goal:
AppModel.php
public function getTranslatedModelField($id = 0, $field) {
$res = false;
$db = $this->getDataSource();
$tmp = $db->fetchAll('SELECT content from s2h_i18n WHERE model = ? AND locale = ? AND foreign_key = ? AND field = ? LIMIT 1',
array($this->alias, Configure::read('Config.language'), $id, $field)
);
if (!empty($tmp)) {
$res = $tmp[0]['s2h_i18n']['content'];
}
return $res;
}
SomeModel.php
public function afterFind($results, $primary = false) {
foreach ($results as $key => $val) {
if (isset($val['SomeOtherModel']) && isset($val['SomeOtherModel']['id'])) {
$results[$key]['SomeOtherModel']['name'] =
$this->SomeOtherModel->getTranslatedModelField($val['SomeOtherModel']['id'], 'name');
}
// other possible queries for other models and/or fields
}
return $results;
}
OK I found a solution. Which is mostly a workaround. I should have thought of that earlier.
What I'm doing is the following. I'm finding all projects and recursively all categories associated with projects. Now since cakephp does not translate categories I am using the results from the initial query and I am performing a second one only for categories but using the category id values that I found on the first query. Now cakephp translates categories since I'm only searching for them and I can have their data translated.
At the moment I'm OK with this solution but it would be nice if first cakephp makes the translate behavior out of the box ready or secondly if someone had a behavior that could support retrieval of translation on associated models.
I generalized the afterFind part a bit, so that it automatically grabs the fields to translate from the associated models' actsAs["Translate"] array, and uses an array of associated models to (potentially) translate:
public function afterFind($results, $primary = false){
$modelsToTranslate = array("SomeModel", "AnotherModel");
foreach ($results as $key => $val){
foreach($modelsToTranslate as $mtt){
if (isset($val[$mtt])){
foreach($val[$mtt] as $fieldname => $fieldval){
foreach ($this->$mtt->actsAs["Translate"] as $fieldToTranslate){
$results[$key][$mtt][$fieldname][$fieldToTranslate] = $this->$mtt->getTranslatedModelField($val[$mtt][$fieldname]['id'], $fieldToTranslate);
}
}
}
}
}
return $results;
}
I took above solution and generalized both functions a bit, now it needs to be used together with the translate behaviour and both functions need to go into the model.php - everything else should work by itself:
public function getTranslatedModelField($id = 0, $field) {
$res = false;
$translateTable = (isset($this->translateTable))?$this->translateTable:"i18n";
$db = $this->getDataSource();
$tmp = $db->fetchAll(
"SELECT content from {$translateTable} WHERE model = ? AND locale = ? AND foreign_key = ? AND field = ? LIMIT 1",
array($this->alias, Configure::read('Config.language'), $id, $field)
);
if (!empty($tmp)) {
$res = $tmp[0][$translateTable]['content'];
}
return $res;
}
public function afterFind($results, $primary = false) {
if($primary == false && array_key_exists('Translate', $this->actsAs)) {
foreach ($results as $key => $val) {
if (isset($val[$this->name]) && isset($val[$this->name]['id'])) {
foreach($this->actsAs['Translate'] as $translationfield) {
$results[$key][$this->name][$translationfield] =
$this->getTranslatedModelField($val[$this->name]['id'], $translationfield);
}
} else if($key == 'id' && is_numeric($val)) {
foreach($this->actsAs['Translate'] as $translationfield) {
$results[$translationfield] =
$this->getTranslatedModelField($val, $translationfield);
}
}
}
}
return $results;
}

Resources