Cakephp: Saving the array value not the integer - php

After filtering some data, i created a variable $customers. This variable is a simple array
which has the following values:
array(
(int) 1 => 'Customer1',
(int) 2 => 'Customer2',
(int) 3 => 'Customer3'
)
I passed this array from the controller to the view like this
$this->set('customers', $customers);
In the view i use this array in a form so that the user can select one
echo $this->Form->input('customer_id', array('options' => array($customers)));
The data which is displayed in the select form is this 'Customer1', 'Customer2', 'Customer3'
Eveyting works ok so far.
Now, after the user has submited the data, i want to do some further logic in the controller. I want to take the data which the user has selected and save it in a second table. So i do this:
$this->Invoice->set('secondtabel', $this->request->data['Invoice']['customer_id']);
The data is being saved in the second table, but the problem is saves the value '1', '2', '3' not the name of the customer. How can i save the name of the customer and not the identifier number from the array.
Please bear with me, i am new to cakephp and to php in general.

I assume this is actually a problem with your HTML, your select box likely looks something like this:
<select name="customer_id">
<option value="1">Customer1</option>
<option value="2">Customer2</option>
<option value="3">Customer3</option>
</select>
This is why your values are 1, 2 or 3 and not Customer1 etc, because $this->request->data['Invoice']['customer_id'] is equal to 1, 2 or 3 etc.
My suggestion would be to fix this at the root of the problem, and I think that by only passing the values into your select box, you should get HTML like this:
<option>Customer1</option>
... which will mean that $this->request->data['Invoice']['customer_id'] will equal Customer1 etc.
So, try this: (array_values will return an array only containing the values, essentially stripping the keys)
$this->set('customers', array_values($customers));
This should fix your problem. However, as far as structured data goes, the way you are currently doing it (storing 1, 2 or 3 etc) is actually the correct way to do this. This way, you simply join the customers table when you are retrieving this data, and you can grab the name that way... Something like this:
$invoices = $this->Invoice->find('all', array(
'conditions' => array(
// your custom find conditions
),
'joins' => array(
array(
'table' => 'customers',
'alias' => 'Customer',
'type' => 'LEFT',
'conditions' => array('Customer.id = Invoice.customer_id')
)
),
'fields' => array(
'Invoice.*', // retrieve regular invoice data
'Customer.name' // retrieve the joined customer name too
)
));
This way you still store a customer ID as an integer, and simply look up the name with SQL when you go to retrieve that data.
A possible reason why you might want to do it simply by storing the customer's name as text is that you want to store the customers name as it appears at the time, meaning if it changes in the future, previous invoices with that name attached won't change with it because that name is stored in text rather than a numeric reference to another table containing a name that has changed.
Hope this helps.
Docs
http://php.net/array_values

Related

Zend2 element/select issue with array

Maybe someone knows how to fix this issue.
For example:
//id in database is 1 (so it should select first element)
$dataArray = [
1 => 'Test 1',
2 => 'Test 2',
3 => '1',
]
$type = new Element\Select('type');
$type->setValueOptions($dataArray);
It will create normal select box, but when data will be auto selected, options will marked as selected 1 and 3 (no matter that's not multi select).
This problem appears when array is loaded from database and value in array is equal for label.
Any help?
Problem solved.
When printing element, value was set like object.

Doctrine: Update using collection

The Problem/How
Pass angularJS the array result of a query that includes many joins.
Using angularJS to sort with ui-sortable reorders the dataset when sorting.
Pass data back to PHP and use synchronizeWithArray to save back (creates a collection).
Doctrine doesn't like receiving the data of the collection back in a different order than it outputs.
** If all I change are values - without reordering elements it saves with no problems.
Update: http://www.doctrine-project.org/jira/browse/DC-346
Noticed it was an old bug they never fixed, is there anything to still do what I want?
Details
$model = Doctrine_Core::getTable('TableName')->findOneById(...);
$model->synchronizeWithArray(array);
$model->save();
Doctrine (1.2) / mysql throws an Integrity error, duplicate primary key id = 2 - it is trying to change the id field.
When I reorder the elements with ui-sortable, it moves the arrays within 'Fields' around while also updating the 'position' value.
This is example data:
The problem would be array 0 and array 1 swap places - causing doctrine to cause primary key error as it tries to change the ids over.
array( // the root of the array is part of one table
id => 1001,
label => 'xxx',
Fields => array( // related table data
0 => array(
id => 1,
position => 0,
name => 'item1'
),
1 => array(
id => 2,
position => 1,
name => 'item2'
),
2 => array(
id => 3,
position => 2,
name => 'item3'
),
3 => array(
id => 4,
position => 3,
name => 'item4'
)
)
)
Well I guess we could either look on the Doctrine side and try to fix this bug, or make it work with the way Doctrine operates. The second option is probably easier.
Why don't you just save the order of the data, and put it back in that order before feeding it back to doctrine? One way to do that would be in angular. Where ever you get the array of data in angular, call saveOrder(), and before feeding it back, call reOrder():
var order = {};
function saveOrder(data)
{
for(var key in data)
{
if(data.hasOwnProperty(key))
{
order[data[key].id] = key;
}
}
}
function reOrder(data)
{
var ordered = [];
for(var key in data)
{
if(data.hasOwnProperty(key))
{
ordered[order[data[key].id]] = data[key];
}
}
return ordered;
}

Retreving specific index from array in CakePHP

I have an array and I would to break it up with out using a foreach loop. I have a query like this:
$pending = $this->Article->find('all', array(
'conditions' => array('Article.status' => 'pending'),
'order' => array('Article.created' => 'desc'), 'limit' =>5
));
Now this brings me back the most recent 5 articles. What I would normally do here is just loop through them and display them, but I want to grab the specific fields for each index separately. How exactly do I do this?
I assumed it was something like:
<?php
echo $this->Html->link($pending['Article'['title'],array('controller'=>
'articles','action'=>'view',$pending['Article']['id'][0]));?>
Where I just add the index to the end of the field I want for that specific element. This doesn't return the right data. How can I do this?
UPDATE:
I was able to figure this out, to grab the specific index from an array in cakephp, you just put the index after your array variable so in this case it would be:
<?php
echo $this->Html->link($pending[0]['Article'['title'],array('controller'=>
'articles','action'=>'view',$pending[0]['Article']['id']));?>
This will go the the numbered index and allow you to grab any part of the array you would like.

PHP Multi-Dimensional Array: Finding a multi-element sub-array match ... is there an alternate option to looping?

We have some customer data which started in a separate data-store. I have a consolidation script to standardize and migrate it into our core DB. There are somewhere around 60,000-70,000 records being migrated.
Naturally, there was a little bug, and it failed around row 9k.
My next trick is to make the script able to pick up where it left off when it is run again.
FYI:
The source records are pretty icky, and split over 5 tables by what brand they purchased ... IE:
create TABLE `brand1_custs` (`id` int(9), `company_name` varchar(112), etc...)
create TABLE `brand2_custs` (`id` int(9), `company_name` varchar(112), etc...)
Of course, a given company name can (and does) exist in multiple source tables.
Anyhow ... I used the ParseCSV lib for logging, and each row gets logged if successfully migrated (some rows get skipped if they are just too ugly to parse programatically). When opening the log back up with ParseCSV, it comes in looking like:
array(
0 => array( 'row_id' => '1',
'company_name' => 'Cust A',
'blah' => 'blah',
'source_tbl' => 'brand1_cust'
),
1 => array( 'row_id' => '2',
'company_name' => 'customer B',
'blah' => 'blah',
'source_tbl' => 'brand1_cust'
),
2 => array( 'row_id' => '1',
'company_name' => 'Cust A',
'blah' => 'blah',
'source_tbl' => 'brand2_cust'
),
etc...
)
My current workflow is along the lines of:
foreach( $source_table AS $src){
$results = // get all rows from $src
foreach($results AS $row){
// heavy lifting
{
}
My Plan is to check the
$row->id and $src->tbl combination
for a match in the
$log[?x?]['row_id'] and $log[?x?]['source_tbl'] combination.
In order to achieve that, I would have to do a foreach($log AS $xyz) loop inside the foreach($results AS $row) loop, and skip any rows which are found to have already been migrated (otherwise, they would get duplicated).
That seems like a LOT of of looping to me.
What about when we get up around record # 40 or 50 thousand?
That would be 50k x 50k loops!!
Question:
Is there a better way for me to check if a sub-array has a "row_id" and "source_tbl" match other than looping each time?
NOTE: as always, if there's a completely different way I should be thinking about this, I'm open to any and all suggestions :)
I think that you should do a preprocessing on the log doing a hash (or composed key) of row_id and source_tbl and store it in an hashmap then for each row just construct the hash of the key and check if it is already defined in the hashmap.
I am telling you to use hashed set because you can search in it with O(k) time otherwise it would be the same as you are proposing only that it would be a cleaner code.

Pagination using multiple searcing criteria in codeigniter

Im trying to implement pagination using multiple searching criteria.
Supposed I Have student table. I also use pagination when the list of student displayed.
The pagination link is. site_url . '/student/page/'; so I use $config['uri_segment'] = 1;
so the pagination link will be
1
2
and son.
After that I wanna search student data using 3 searching criteria implemented using textfield.
id name address.
user can search by id or name or address or combination of the three criteria.
the url become
http://mysite/index.php/student/page/0
href=http://mysite/index.php/student/page/1
and son.
but I use get method for searching. and while trying to search using the search criteria field the url become
href="http://mysite/index.php/student/page/1?id=1&name=a&address=b
the problem occurred when I try create pagination based on criteria. because the pagination link have contain query string
i don't know how to create become
href="http://mysite/index.php/student/page/0?id=1&name=a&address=b
href="http://mysite/index.php/student/page/1?id=1&name=a&address=b
or do you have a best practice to solve this problem ?
Hi phill ....
I have try your suggestion.
$array = array('id' => '001', 'name' => 'a', 'address' => 'canada');
the url become
id/001/name/a/address/canada. I use $this->uri->uri_to_assoc() function to get key and value of the segment.
array (
id => 001,
name=>a,
address=>canada
)
but while there some searching criteria that not included while searching. let say, the user only search by name and address. the array become
$array = array('id' => '', 'name' => 'a', 'address' => 'canada'); and the url id/name/a/address/canada
the assoc array become
array (
id => name,
a=>address,
canada=>
)
the assoc array is not disorganized again. so I can't get the right value of the assoc array.
I think i will set the identifier to the searching criteria if not included. supposed i put #.
if isset($_GET['id']) then
$id = '#'
else
$id = $_GET['id']
$array = array('id' => $id, 'name' => 'a', 'address' => 'canada');
How about that ... ? or if there are another best practice ?
For that I would use $this->uri->uri_to_assoc():
index.php/user/search/name/joe/location/UK/gender/male
Using this function you can turn the
URI into an associative array with
this prototype:
[array]
(
'name' => 'joe'
'location' => 'UK'
'gender' => 'male'
)
See the full documentation here.
You can still use page/1 as the first lot then have /name/whatever afterwards.
Actualy, we can create pagination with multiple and unlimited criteria. Read here http://dengkul.com/2010/07/08/codeigniter-pagination-with-multiple-unlimited-searching-criteria/

Categories