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;
}
Related
I'm using CodeIgniter framework for the easyappointments.org library. I'm trying to update the field data through the id of a row. Actually this is my code for the update:
return $this->db
->update('ea_appointments', $appointment)
->where('ea_appointments.id', $appointment_id);
The problem's that the update method need two parameter (table to update, associative array with the fields name column of db). In my above function I pass only the $appointment_id, so the variable $appointment is empty and doesn't contain any associative array. I want to know how to update only the field data to 1. And remain the other field in the same value condition.
This is the structure of the table:
id|book|start|end|notes|hash|unavailable|provider|data
Logic example:
previous condition row:
id => 0
book => example
start => 18/10/2015
end => 19/10/2015
notes => empty
hash => akdjasldja
unavailable => false
provider => 5
data => 0
I pass in the function $appointment_id with 0 value. I'm waiting this new result:
id => 0
book => example
start => 18/10/2015
end => 19/10/2015
notes => empty
hash => akdjasldja
unavailable => false
provider => 5
data => 1
So the main problem is retrieve first the all field value of the specific row and later update? Or something like this. Could someone help me?
In my above function I pass only the $appointment_id, so the variable
$appointment is empty and doesn't contain any associative array.
If you simply want to update the column data to 1 for appointment_id 0 then pass in an array with data for the key and 1 for the value.
$appointment_id = 0;
$appointment = array('data' => 1);
$this->db->where('id', $appointment_id);
$this->db->update('ea_appointments', $appointment);
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
I want to insert the records (that i got from a table) to another table using codeigniter.
here's the function to add the record. I pass the $nokw to insert to another table as foreign key.:
function add_detail($nokw){
$id_sj = $this->session->userdata('id');
$upddate = date('Y')."-".date('m')."-".date('d')." ".date('H').":".date('i').":".date('s');
$i=0;
$this->suratjalan->where('IDDeliveryNo',$id_sj);
$rec = $this->suratjalan->get("t02deliveryno_d")->result_array();
// parse the result and insert it into an array
foreach ($rec as $det){
$i++;
$detail[$i] = array(
'ID' => '',
'NoKwitansi' => $nokw,
'TypeProduct'=> $det['TypeProduct'],
'PartNo' => $det['PartNo'],
'PartNoVendor'=> $det['PartNoVendor'],
'SerialPanel' => $det['SerialPanel'],
'Description' => $det['Description'],
'Dimension' => $det['Dimension'],
'DescriptionVendor' => $det['DescriptionVendor'],
'DimensionVendor' => $det['DimensionVendor'],
'PrintedProduct' => $det['PrintedProduct'],
'Qty' => $det['Qty'],
'UoM' => $det['UoM'],
'Remark' => $det['Remark'],
'UpdUser'=> $this->session->userdata('user'),
'UpdDate'=> $upddate
);
// insert the record
$this->finance->insert('t02fkpd',$detail[$i]);
}
}
It works, but it doesn't work if more than one row is returned from the table 't02deliveryno_d'. I think the error comes when i insert the record. i use the $i++to make different index in $detail array.
How can I fix this to properly insert multiple rows?
You didn't show the db schema, but I'm assuming that t02fkpd.ID is an auto-incrementing column.
If that's the case, the problem is that you're specifying a blank value for ID instead of letting the database handle it. This is probably resulting in attempts to insert duplicate rows with the same (blank) id.
Here's an updated version of your function that I suspect will work better:
function add_detail($nokw) {
$id_sj = $this->session->userdata('id');
$upddate = date('Y-m-d H:i:s');
$this->suratjalan->where('IDDeliveryNo',$id_sj);
$rec = $this->suratjalan->get("t02deliveryno_d")->result_array();
foreach ($rec as $det) {
$details = array(
'NoKwitansi' => $nokw,
'TypeProduct'=> $det['TypeProduct'],
'PartNo' => $det['PartNo'],
'PartNoVendor'=> $det['PartNoVendor'],
'SerialPanel' => $det['SerialPanel'],
'Description' => $det['Description'],
'Dimension' => $det['Dimension'],
'DescriptionVendor' => $det['DescriptionVendor'],
'DimensionVendor' => $det['DimensionVendor'],
'PrintedProduct' => $det['PrintedProduct'],
'Qty' => $det['Qty'],
'UoM' => $det['UoM'],
'Remark' => $det['Remark'],
'UpdUser'=> $this->session->userdata('user'),
'UpdDate'=> $upddate
);
$this->finance->insert('t02fkpd',$details);
}
}
Beyond removing the ID value, I also made the following minor changes:
I removed $i and just reused the same variable for building the array of values to insert. You're not using the array after you insert, so there's no need to build a list of all the rows - you can just overwrite it each time.
I changed your the $upddate calculation to only call date() once. You can specify an entire format string in one call - you're not restricted to just a single character at a time.
I haven't get your question properly. But i think http://ellislab.com/codeigniter/user-guide/database/active_record.html#insert with definitely help you.
You can make a array and pass it to insert_batch function with the table name and array. This will definitely help you.
if you must have checked user-guide for codeigniter. its one of the good documentation, where each and every function is documented.
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.
I have an array in PHP that is simply strings. These strings represent relationships that can occur between different distances of family. It looks like this:
0 => 'Unknown',
1 => 'Parent',
2 => 'Grandparent',
3 => 'Sibling',
4 => 'Child',
5 => 'Grandchild',
6 => 'Spouse',
7 => 'Self',
9 => 'Step Parent',
10 => 'Step Sibling',
11 => 'Step Child',
etc...
This array works great, but I'm running into a problem where I would like to be able to sort these items in a purely custom way (specifically closer-to-father away starting with Spouse/Sibling ending with most distant relations like X-in-law), but I also would like the list to be added to over time. My initial thought was to simply order them as they needed to be ordered in the array, but that does not allow me to add relations at a later date (though it's doubtful this would ever happen, I'd rather be safe than sorry). The best solution I could come up with (an seemingly a good one in my mind) was to make a simple PHP object that would hold both the name of the relation and an arbitrary "sort" value like this new Relation('Unknown', 0);. The problem is, it appears that you cannot instantiate objects while making an array with the X => Y syntax, as I have syntax errors when I try to write this:
0 => new Relation('Unknown', 0),
1 => new Relation('Grandparent', 1),
etc...
Is there a way that this could work or possibly a better solution? It seems at this point I may have to generate the array the first time it is requested (in a getter) using Array pushes then store it, but I'd rather have it nicely formatted. Am I just out of luck?
Edit - To clarify: The keys right now are being used as the stored value in the database. In essence, we are using the array as an enum in other languages.
Use the array as a map, such as relationship_name => relationship_distance. If it is more convenient, you can do relationship_distance => relationship_name. Make the relationship_distance values arbitrary, with gaps in between so that intermediate distances can be added later. For example:
'Sibling' => 1,
'Parent' => 10,
'Grandparent' => 20,
'Greatgrandparent' => 30,
'Uncle' => 13,
'BrotherInLaw' => 17,
Then you can sort the map by they keys or the values and add new entries as needed.
You could write this in a array. What happens to be a syntax error is if you wrote that in a class property.
You can't do this:
class A {
public $relations = array(
0 => new Relation('Unknown', 0),
1 => new Relation('Grandparent', 1)
);
}
But you could do the init in the constructor.
class A {
public $relations;
public function __construct() {
$this->relations = array(
0 => new Relation('Unknown', 0),
1 => new Relation('Grandparent', 1)
);
}
}
PS: if the keys is just 0,1,... you could omit them.