Array category subcategory - arrays

I have this category and subcategory table.
The field that has the value NULL for parent_id is a category, and the ones that use parent_id are subcategories.
My tree view has subcategories assigned only to categories, so no subcategories for subcategories.
+----+---------------------+-----------+
| id | name | parent_id |
+----+---------------------+-----------+
| 1 | Laptop | NULL |
| 2 | TV | NULL |
| 3 | Tablet & Mobile | NULL |
| 4 | PC | NULL |
| 5 | Laptops | 1 |
| 6 | Laptop accessories | 1 |
| 7 | TV accessories | 2 |
If I do a SELECT * and spice it with a while I get the following array.
'category' => [
{
'name' => 'Laptop',
'id' => '1',
'parent_id' => undef
},
{
'name' => 'TV',
'id' => '2',
'parent_id' => undef
},
{
'name' => 'Table & mobile',
'id' => '3',
'parent_id' => undef
},
{
'name' => 'PC',
'id' => '4',
'parent_id' => undef
},
{
'name' => 'Laptops',
'id' => '5',
'parent_id' => '1'
},
{
'name' => 'Laptop accessories ',
'id' => '6',
'parent_id' => '1'
},
{
'name' => 'TV accessories',
'id' => '7',
'parent_id' => '2'
}
The structure I'm looking for should look like this.
category 1
-- subcategory 1.1
-- subcategory 1.2
category 2
-- subcategory 2.1
What I get now looks like
category 1
subcategory 1.1
category 2
subcategory 1.2
subcategory 2.1

#!/usr/bin/perl
use strict;
use warnings;
my %struct = (category => [
{
'name' => 'Laptop',
'id' => '1',
'parent_id' => undef
},
{
'name' => 'TV',
'id' => '2',
'parent_id' => undef
},
{
'name' => 'Table & mobile',
'id' => '3',
'parent_id' => undef
},
{
'name' => 'PC',
'id' => '4',
'parent_id' => undef
},
{
'name' => 'Laptops',
'id' => '5',
'parent_id' => '1'
},
{
'name' => 'Laptop accessories ',
'id' => '6',
'parent_id' => '1'
},
{
'name' => 'TV accessories',
'id' => '7',
'parent_id' => '2'
}
]);
my %tree;
for my $cat (grep ! defined $_->{parent_id}, #{ $struct{category} }) {
$tree{ $cat->{id} } = $cat;
}
for my $cat (grep defined $_->{parent_id}, #{ $struct{category} }) {
$tree{ $cat->{parent_id} }{subcat}{ $cat->{id} } = $cat;
}
use Data::Dumper; print Dumper \%tree;

Related

CakePHP 3 updating data in the join table

I'm having trouble updating existing data in my join table. Here it goes...
I have 2 models SalesOrders and Products that have a belongsToMany association through LineItems.
products
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | int(11) | NO | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
sales_orders
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| order_number | int(11) | NO | | NULL | |
+--------------+---------------------+------+-----+---------+----------------+
line_items
+----------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| sales_order_id | int(11) unsigned | NO | | NULL | |
| product_id | int(11) unsigned | NO | | NULL | |
| qty | int(11) | NO | | NULL | |
+----------------+---------------------+------+-----+---------+----------------+
Creating a new sales order works as expected. I can add multiples products and quantities to a sales order on the add new sales order page. All the correct data is added to the join table.
The problem I'm having is when I try to edit an existing sales order. For example, I want to change the quantity of a certain line item from 5 to 2. I open the edit page for the sales order I wish to modify, change the quantity on the desired line item, and submit the form. The form submits successfully but the join table is not updated. This seems like pretty basic functionality that I can't get working. All of my code was baked with a few small modifications.
SalesOrdersTable:
$this->belongsToMany('Products', [
'foreignKey' => 'sales_order_id',
'targetForeignKey' => 'product_id',
'through' => 'LineItems',
]);
ProductsTable:
$this->belongsToMany('SalesOrders', [
'foreignKey' => 'product_id',
'targetForeignKey' => 'sales_order_id',
'through' => 'LineItems',
]);
LineItemsTable:
$this->belongsTo('Products', [
'foreignKey' => 'product_id',
'joinType' => 'INNER'
]);
$this->belongsTo('SalesOrders', [
'foreignKey' => 'sales_order_id',
'joinType' => 'INNER'
]);
SalesOrdersController edit:
public function edit($id = null)
{
$salesOrder = $this->SalesOrders->get($id, [
'contain' => ['Products']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$salesOrder = $this->SalesOrders->patchEntity($salesOrder, $this->request->data);
if ($this->SalesOrders->save($salesOrder)) {
$this->Flash->success(__('The sales order has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The sales order could not be saved. Please, try again.'));
}
}
$products = $this->SalesOrders->Products->find('list', ['limit' => 200]);
$this->set(compact('salesOrder', 'products'));
$this->set('_serialize', ['salesOrder']);
}
SalesOrders template edit.ctp
echo $this->Form->input('order_number');
echo $this->Form->input('products.0.id', [
'type' => 'select',
'options' => $products
]);
echo $this->Form->input('products.0._joinData.qty');
The SalesOrder entity looks like this when submitting the form to change the quantity from 5 to 2.
object(App\Model\Entity\SalesOrder) {
'id' => (int) 1,
'order_number' => 'SO1111',
'products' => [
(int) 0 => object(App\Model\Entity\Product) {
'id' => '1',
'name' => 'Acme Widget 1',
'_joinData' => object(App\Model\Entity\LineItem) {
'id' => (int) 1,
'product_id' => (int) 1,
'sales_order_id' => (int) 1,
'qty' => (int) 2,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'qty' => true
],
'[original]' => [
'qty' => (int) 5
],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'LineItems'
},
'[new]' => false,
'[accessible]' => [
'*' => true,
'_joinData' => true
],
'[dirty]' => [
'_joinData' => true
],
'[original]' => [
'_joinData' => object(App\Model\Entity\LineItem) {
'id' => (int) 1,
'product_id' => (int) 1,
'sales_order_id' => (int) 1,
'qty' => (int) 2,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'qty' => true
],
'[original]' => [
'qty' => (int) 5
],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'LineItems'
}
],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Products'
}
],
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'SalesOrders'
}
As you can see the dirty property on the SalesOrder is empty. It's not picking up that the Products _joinData has been modified.
If I add $salesOrders->dirty('products', true); just before save() is called then join table gets updated. While this works, and I could write some logic to handle the update this way, I feel there is better/proper way to do this.
Any help is appreciated, thanks in advance.
Turns out this was a cake bug in 3.3 that wasn't resolved until the 3.3.2 release. Once I updated everything worked as expected. github.com/cakephp/cakephp/pull/9276

recursive 2 with Cakephp functional

I need to build a select drop-down list from data from find().
When I perform a recursive find:
$parlamentarios = $this->Revocatorio->Parlamentario->find('all', array('recursive' => 2));
It returns the following:
array(
(int) 0 => array(
'Parlamentario' => array(
'id' => '1',
'postulacion_id' => '4',
'created' => '2016-01-10 20:29:47',
'periodo_id' => '1',
'voto_parlamento' => '4000'
),
'Postulacion' => array(
'id' => '4',
'registro_id' => '2',
'comite_id' => '5',
'periodo_id' => '1',
'fecha_elec' => '2016-01-23',
'created' => '2016-01-03 20:40:18',
'voto' => '0',
'Registro' => array(
'id' => '2',
'cedula' => '',
'nacionalidad' => '1',
'nombre' => '',
'seg_nombre' => '',
'apellido' => '',
'seg_apellido' => '',
'genero' => true,
'fecha_nac' => '-',
'lugar_nac' => 'Portuguesa',
'fecha_reg' => '2015-12-02',
'direccion' => 'aijhaoihdwaoih',
'edad' => '21',
'foto' => '1 LOGO UNERG.jpg',
'foto_dir' => '2',
'leer' => true,
'escribir' => true,
'discapacidad' => 'ninguna',
'aptitud' => true,
'estado_civil' => 'Casado/a',
'ccregistro_id' => '0',
'name' => ' - '
),
'Comite' => array(
'id' => '5',
'comite' => 'awdawdawdawd'
),
'Periodo' => array(
'id' => '1',
'periodo' => '2015-2017'
),
'Escrutinio' => array(),
'Revocatorio' => array()
),
'Periodo' => array(
'id' => '1',
'periodo' => '2015-2017',
'Ccregistro' => array(),
'Escrutinio' => array(),
'Postulacion' => array(
(int) 0 => array(
'id' => '2',
'registro_id' => '3',
'comite_id' => '3',
'periodo_id' => '1',
'fecha_elec' => '2015-12-24',
'created' => '2015-12-22 05:42:21',
'voto' => '200'
),
(int) 1 => array(
'id' => '3',
'registro_id' => '2',
'comite_id' => '1',
'periodo_id' => '1',
'fecha_elec' => '2016-01-20',
'created' => '2016-01-03 05:46:46',
'voto' => '0'
),
(int) 2 => array(
'id' => '4',
'registro_id' => '2',
'comite_id' => '5',
'periodo_id' => '1',
'fecha_elec' => '2016-01-23',
'created' => '2016-01-03 20:40:18',
'voto' => '0'
),
(int) 3 => array(
'id' => '5',
'registro_id' => '3',
'comite_id' => '9',
'periodo_id' => '1',
'fecha_elec' => '2016-01-21',
'created' => '2016-01-03 20:41:03',
'voto' => '0'
),
(int) 4 => array(
'id' => '6',
'registro_id' => '3',
'comite_id' => '11',
'periodo_id' => '1',
'fecha_elec' => '2016-01-14',
'created' => '2016-01-03 21:06:27',
'voto' => '0'
),
(int) 5 => array(
'id' => '7',
'registro_id' => '2',
'comite_id' => '1',
'periodo_id' => '1',
'fecha_elec' => '2016-01-22',
'created' => '2016-01-04 02:38:17',
'voto' => '0'
)
)
),
'Escrutinio' => array(),
'Revocatorio' => array()
),
The relationships are:
Revocatorio hasMany Parlamentario
Parlamentario hasMany Postulacion
Postulacion hasMany Registro
I need save the id of Parlamentario, but show Postulacion.Registro.name in add view. How can I accomplish this?
Try this:
$this->Parlamentario->find("list", array(
"fields" => array("Parlamentario.id", "Postulacion.Registro.name"),
"contain" => array("Postulacion.Registro")
)
);
Peace! xD

perl group results in hash using fetchrow_hashref

I want to group my results by countryid with the data shown below.
my #test = ();
my $st = qq[
SELECT id,countryID,abbrev
FROM myTable
];
my $q = $data->prepare($st);
$q->execute() or query_error($st);
while ( my $result = $q->fetchrow_hashref ) {
push #test, $result;
}
Using fetchrow_hashref I have no problem displayling the results
use Data::Dumper;
print STDERR Dumper(\#test);
returns
$VAR1 = [
{ 'id' => '1',
'countryID' => '1',
'title' => 'Title 1',
'abbrev' => 't1'
},
{ 'id' => '2',
'countryID' => '2',
'title' => 'Title 2',
'abbrev' => 't2'
},
{ 'id' => '3',
'countryID' => '3',
'title' => 'Title 3',
'abbrev' => 't3'
},
{ 'id' => '4',
'countryID' => '1',
'title' => 'Title 4',
'abbrev' => 't4'
}
];
I want to group it by countries as shown below.
$VAR1 = [
'countries' => {
'1' => [
{ 'id' => '1',
'title' => 'Title 1',
'abbrev' => 't1'
},
{ 'id' => '4',
'title' => 'Title 4',
'abbrev' => 't4'
}
],
'2' => [
{ 'id' => '2',
'title' => 'Title 2',
'abbrev' => 't2'
}
],
'3' => [
{ 'id' => '3',
'title' => 'Title 3',
'abbrev' => 't3'
}
]
}
];
How can I get this working in the while loop?
Ignoring the errors in your sample data structure, you are basically looking to convert form array of hashes to hash of hash of array of hashes. Once you have your initial data structure setup, you can do the following to create your new nested data structure:
for my $href ( #test ) {
my $id = $href->{countryID};
delete $href->{countryID};
push #{ $test2->{countries}{$id} }, $href;
}
Iterate each element of your array #test which basically is an array of hash references. Create a variable $id which will capture the countryID value from the hash. We delete it from the hash reference and then assign that hash reference to our new nested data structure which has countries as the first level key and the $id as the second level key.
We use push syntax to create our array of such references.
Note: As stated by thb in the comments, this does destroys your original data structure. If you'd like to retain the original structure, modify the code to the following:
for my $href ( #test ) {
my $copy = { %$href };
my $id = $copy->{countryID};
delete $copy->{countryID};
push #{ $test2->{countries}{$id} }, $copy;
}
You'll need to fix your syntax above a little (for example => instead of = >), but once you have done that, something like this should work nicely.
for (#$VAR1_orig) {
my %a = %$_;
my $countryID = $a{countryID};
delete $a{countryID};
push #{$VAR1->{countries}{$countryID}}, \%a;
}
(I have tried it on my computer, incidentally. It works.)
The above assumes that %$VAR1 is initially empty, then populates it according to #$VAR1_orig, after which you can do with $VAR1 whatever you like. (I assume that you know what %$ and #$ mean in Perl, but this is not a beginner's topic, as you may know. See man 1 perlref.)
Something like this, the input/output data structures might not be exactly what you have or want, you can patch that up.
use strict;
use Data::Dumper;
$a = [
{ 'id' => '1',
'countryID' => '1',
'title' => 'Title 1',
'abbrev' => 't1'
},
{ 'id' => '2',
'countryID' => '2',
'title' => 'Title 2',
'abbrev' => 't2'
},
{ 'id' => '3',
'countryID' => '3',
'title' => 'Title 3',
'abbrev' => 't3'
},
{ 'id' => '4',
'countryID' => '1',
'title' => 'Title 4',
'abbrev' => 't4'
}
];
my $b = {};
for my $item (#$a) {
if ( exists( $b->{ $item->{'countryID'} } ) ) {
push( #{ $b->{ $item->{'countryID'} } }, $item );
} else {
$b->{ $item->{'countryID'} } = [$item];
}
}
print Dumper($b);
The above prints:
$VAR1 = {
'1' => [
{ 'abbrev' => 't1',
'title' => 'Title 1',
'id' => '1',
'countryID' => '1'
},
{ 'abbrev' => 't4',
'title' => 'Title 4',
'id' => '4',
'countryID' => '1'
}
],
'3' => [
{ 'abbrev' => 't3',
'title' => 'Title 3',
'id' => '3',
'countryID' => '3'
}
],
'2' => [
{ 'abbrev' => 't2',
'title' => 'Title 2',
'id' => '2',
'countryID' => '2'
}
]
};

how i can fetch user data in a manyToMany association

I have a problem with CakePHP. I tested many ways, but can't find a solution for it.
I have these tables:
users
id
name
country_code
countries
code
title
skills
code
title
roles
id
title
events
id
title
country_code
events_users
event_id
user_id
role_id
skill_code
events hasAndBelongsToMany users and events_users is my join table, and when I read data, it gives me something like this:
array(
(int) 0 => array(
'Event' => array(
'id' => '1',
'title' => '40th WorldSkills Competitions',
'year' => '2011',
'country_code' => 'LV',
'created' => '2013-02-08 00:00:00'
),
'User' => array(
(int) 0 => array(
'password' => '*****',
'id' => '14',
'name' => 'test',
'family' => 'testian',
'username' => 'test#mail.me',
'country_code' => 'BR',
'telphone' => '465465',
'avatar' => 'avatar_51299c1da268f20110912043238_rodekamp_04.jpg',
'address' => 'AA',
'admin' => '0',
'created' => '2013-02-24 05:50:37',
'modified' => '2013-02-24 05:50:37',
'EventsUser' => array(
'id' => '1',
'user_id' => '14',
'event_id' => '1',
'role_id' => '1',
'skill_code' => '17',
'manage' => '100'
)
),
(int) 1 => array(
'password' => '*****',
'id' => '5',
'name' => 'John',
'family' => 'Smith',
'username' => 'john#me.com',
'country_code' => 'IE',
'telphone' => '147',
'avatar' => '20120504124040_franziska_peter_ok.jpg',
'address' => 'No 55',
'admin' => '0',
'created' => '2013-02-10 15:24:13',
'modified' => '2013-02-10 15:28:50',
'EventsUser' => array(
'id' => '2',
'user_id' => '5',
'event_id' => '1',
'role_id' => '2',
'skill_code' => '17',
'manage' => '0'
)
),
(int) 2 => array(
'password' => '*****',
'id' => '4',
'name' => 'hadi',
'family' => 'mm',
'username' => 'design.zerzem#gmail.com',
'country_code' => 'AE',
'telphone' => '415456',
'avatar' => '',
'address' => 'sadjfklsaf asd f',
'admin' => '0',
'created' => '2013-02-10 09:01:28',
'modified' => '2013-02-24 06:43:42',
'EventsUser' => array(
'id' => '3',
'user_id' => '4',
'event_id' => '1',
'role_id' => '4',
'skill_code' => '17',
'manage' => '0'
)
)
)
It's ok, but with events_users I want get data about skill and role that are in events_users (skill_code and role_id). How should I create models to give me all this data?
I think reading about "hasMany Through" should answer your question.
Basically, you make a model for your join table, then you can associate it like any other model.
When you go to retrieve your data, use CakePHP's Containable behavior (if you haven't used it before, be prepared to get addicted to it).

CakePHP: testing -> ValidationException

I'm new to programming and testing. I'm stuck at this testing, which throws an exception.
Please help me as I really don't get how I should approach this question.
My method to test:
public function saveNewInstitution($institutionData, $user) {
$institutionData[$this->alias]['isActive'] = 1;
$institutionData[$this->alias]['users_id'] = $user['User']['id'];
$this->create();
$this->set($institutionData);
if ($this->validates()) {
return $this->save();
} else {
throw new ValidationException('Not all fields are filled out correct');
}
}
My testclass:
public function testSaveNewInstitution() {
$result = array(
'Institution' => array(
'id' => 2,
'name' => 'Spitex',
'address' => 'Hauptweg 4',
'postcode' => '1234',
'city' => 'huuh',
'phone_number' => '123 456 78 90',
'email' => 'staufen#tsdy.huuh',
'comment' => '',
'isActive' => TRUE,
'users_id' => 2,
'institution_types_id' => 5
),
'Users' => array(
'id' => 2,
'email' => 'herbert#xyz.ch',
'password' => AuthComponent::password('12345678'),
'isMale' => TRUE,
'first_name' => 'Herbert',
'last_name' => 'Müller',
'address' => 'Hauptstrasse 1',
'postcode' => '1234',
'city' => 'Zürich',
'phone_number' => '123 456 78 90',
'isActive' => FALSE,
'institutions_id' => 2,
'groups_id' => 4
),
'InstitutionTypes' => array(
'id' => 5,
'name' => 'Spitex'
),
'Assignee' => array('0' => array(
'id' => 2,
'email' => 'herbert#xyz.ch',
'password' => AuthComponent::password('12345678'),
'isMale' => TRUE,
'first_name' => 'Herbert',
'last_name' => 'Müller',
'address' => 'Hauptstrasse 1',
'postcode' => '1234',
'city' => 'Zürich',
'phone_number' => '123 456 78 90',
'isActive' => FALSE,
'institutions_id' => 2,
'groups_id' => 4
))
);
$expected = $this->Institution->saveNewInstitution($result, 2);
$this->assertEqual($result, $expected);
}
public function testSaveNewInstitutionException() {
$this->setExpectedException('ValidationException');
$expected = array(
'Institution' => array(
'id' => 2,
'name' => 'Spitex',
'address' => 'Hauptweg 4',
'postcode' => '1234',
'city' => 'huuh',
'phone_number' => '123 456 78 90',
'email' => 'staufen#xyz.huuh',
'comment' => '',
'isActive' => TRUE,
'users_id' => 2,
'institution_types_id' => 5
),
'Users' => array(
'id' => 2,
'email' => 'herbert#xyz.ch',
'password' => AuthComponent::password('12345678'),
'isMale' => TRUE,
'first_name' => 'Herbert',
'last_name' => 'Müller',
'address' => 'Hauptstrasse 1',
'postcode' => '1234',
'city' => 'Zürich',
'phone_number' => '123 456 78 90',
'isActive' => FALSE,
'institutions_id' => 2,
'groups_id' => 4
),
'InstitutionTypes' => array(
'id' => 5,
'name' => 'Spitex'
),
'Assignee' => array('0' => array(
'id' => 2,
'email' => 'herbert#mueller.ch',
'password' => AuthComponent::password('12345678'),
'isMale' => TRUE,
'first_name' => 'Herbert',
'last_name' => 'Müller',
'address' => 'Hauptstrasse 1',
'postcode' => '1234',
'city' => 'Zürich',
'phone_number' => '123 456 78 90',
'isActive' => FALSE,
'institutions_id' => 2,
'groups_id' => 4
))
);
$this->Institution->saveNewInstitution($expected, 2);
}
My exception:
**VALIDATIONEXCEPTION**
Not all fields are filled out correct
Test case: InstitutionTest(testSaveNewInstitution)
Stack trace:
/app/Test/Case/Model/InstitutionTest.php : 148
InstitutionTest::testSaveNewInstitution
/usr/lib/php/PHPUnit/Framework/TestCase.php : 969
/usr/lib/php/PHPUnit/Framework/TestCase.php : 824
/usr/lib/php/PHPUnit/Framework/TestResult.php : 648
/usr/lib/php/PHPUnit/Framework/TestCase.php : 769
/lib/Cake/TestSuite/CakeTestCase.php : 78
/usr/lib/php/PHPUnit/Framework/TestSuite.php : 775
/usr/lib/php/PHPUnit/Framework/TestSuite.php : 745
/usr/lib/php/PHPUnit/TextUI/TestRunner.php : 346
/lib/Cake/TestSuite/CakeTestRunner.php : 57
/lib/Cake/TestSuite/CakeTestSuiteCommand.php : 111
/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php : 242
/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php : 99
/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php : 116
/app/webroot/test.php : 92
9/9 test methods complete: 8 passes, 0 fails, 12 assertions and 1 exceptions.
as stated in the comments, the issue is pretty straigt forward. your validation fails and therefore the exception is thrown (as desired by your code).
if you want to debug it, try to determine what
$this->validationErrors
contains after the save() (before/instead of throwing the exception). then you know why the validation fails.

Resources