Gossamer Forum
Home : Products : Gossamer Links : Development, Plugins and Globals :

Question only for experts.

Quote Reply
Question only for experts.
The following is a global i've been working on today, what it does is display a pulldown menu of all categories that contain links with a certain criteria, usefull if you plan to have multiple types of records in your links SQL instalation. But.. I've a small problem... at the end of the code you'll see a sort routine

I took almost all of this from Links SQL code, but I don't understand how to sort the pulldown by name and indent the subcategories like this:

MAIN CATEGORY1
.....Subcategory
.....Subcategory

MAIN CATEGORY2
.....Subcategory
.....Subcategory

As you can see with the code I had to place the ident field on the right. There's NO WAY a Can ident the fields and sort it by name properly. can somebody give me a hand?


Code:

sub {

#################################################################

# SHOW ONLY CATEGORIES THAT CONTAIN LINKS OF TYPE $LinkType #

#################################################################

my $onlyroot = 0; # set to 1 for displaying root categories only

my $mult = 1; # Number of columns

my $margin = " >>>> ";

###############################################################

my ($rec) = @_;

my $LinkType = $rec->{LinkType} || 'Regular';

my ($name,$id,$category,$ident);

my $db = $DB->table('Category');

my $self = $DB->html($db, $IN);

my $sth = $db->select ( ['ID', 'Full_Name', 'FatherID'] );

my $cat_link = $DB->table('CatLinks', 'Links', 'Category');

my %res = ();

my %sortby = ();

while (my ($id, $name, $tags) = $sth->fetchrow_array) {

my $child_total = $cat_link->count(GT::SQL::Condition->new(['Full_Name', 'LIKE', "$name/%"], ['isValidated', '=', 'Yes'], ['LinkType', '=', "$LinkType"]));

my $root_total = $cat_link->count({ LinkType => $LinkType, isValidated => 'Yes', 'Links.ID' => $id });

my $total_acum = ($child_total + $root_total);

$ident = "";

if ($tags == 0) {$ident = "$margin"}

if ($onlyroot == 1) {

if (($total_acum > 0) && ($tags == 0)) {

$res{$id} = "$name $ident";

$sortby{$id} = "$name";

}

}

else {

if ($total_acum > 0) {

$res{$id} = "$name $ident";

$sortby{$id} = "$name";

}

}

}

return $self->select ( { name => $name, values => \%res, value => $id, multiple => $mult , sort => sub { lc $_[0] cmp lc $_[1] } } );

}

Last edited by:

jaltuve: Mar 28, 2003, 4:41 PM
Quote Reply
Re: [jaltuve] Question only for experts. In reply to
If I understood your problem correctly, here are few ideas for you.

Your example only works fine for a few level deep...:
MAIN CATEGORY1
.....Subcategory
.....Subcategory
So depends on how deep is your category list. What you do for a 10-20 level deep example? It will be looped into next row, so will become unreadable...
So what you need to analyze first is, how deep is your category list? Then start planning.

I did not analyzed your code, but here's a short synapse of my algorythm logic.

1) Get the category full name
2) Split by /
3) return each Name, by adding one more indenting for each / sign...

The core of that synapse code is something like that (Only for 1 category. You need a loop cycle for each category):
Code:
my @levels = split /\//, $Full_name; # previously you get Full_name from DB
my $level_num = scalar @levels;
my $indent = '    ';
my $output;
foreach my $name (@levels) {
$output .= ($level_num) x $indent . $name;
}
$output .= '<br>'; # finished this category name by new line
(EDIT: Don't use this code, there was a mistake in it! Use the one listed in post #4)

This is just an example.
The code syntactically is not correct for sure, but gives you a starting point where to begin...
Good luck!

Best regards,
Webmaster33


Paid Support
from Webmaster33. Expert in Perl programming & Gossamer Threads applications. (click here for prices)
Webmaster33's products (upd.2004.09.26) | Private message | Contact me | Was my post helpful? Donate my help...

Last edited by:

webmaster33: Mar 29, 2003, 9:28 AM
Quote Reply
Re: [webmaster33] Question only for experts. In reply to
That won't do as he wants as if you select a top level category that has two subcategories your output will be:

Code:
Category One
Sub Category One
Category One
Sub Category Two

...whereas I think he wants something like:

Code:
Category One
Sub Category One
Sub Category Two
Quote Reply
Re: [Paul] Question only for experts. In reply to
No, the example code gave much worse result, since there was no need for the foreach loop...

Got corrected:
Code:
my @levels = split /\//, $Full_name; # previously you get Full_name from DB
my $level_num = scalar @levels;
my $indent = '&nbsp;&nbsp;&nbsp;&nbsp;';
$output .= ($level_num) x $indent . $Name . '<br>'; # previously you get Name from DB
# then loop this for each category

Best regards,
Webmaster33


Paid Support
from Webmaster33. Expert in Perl programming & Gossamer Threads applications. (click here for prices)
Webmaster33's products (upd.2004.09.26) | Private message | Contact me | Was my post helpful? Donate my help...

Last edited by:

webmaster33: Mar 29, 2003, 9:23 AM
Quote Reply
Re: [webmaster33] Question only for experts. In reply to
If you have:

Category_One/SubCategory_One
Category_One/SubCategory_Two
Category_One/SubCategory_Three

...then the desired output is:

Code:
Category_One
SubCategory_One
SubCategory_Two
SubCategory_Three

...but if my analysis of your code is correct, then it certainly won't do that.

If $Full_Name was "Category_One" then @levels would be 1 and so the output would be:

&nbsp;&nbsp;&nbsp;&nbsp;Category_One

It doesn't select any sub-categories to list them.
Quote Reply
Re: [Paul] Question only for experts. In reply to
Paul, it's not my job, to work out his correct solution.
I gave him an example, and the rest is his task... I don't have more time to work out him an exact solution, especially that he knows what he really need.

Paul, if you have so much free time, you are free to work out the final code for him...

Best regards,
Webmaster33


Paid Support
from Webmaster33. Expert in Perl programming & Gossamer Threads applications. (click here for prices)
Webmaster33's products (upd.2004.09.26) | Private message | Contact me | Was my post helpful? Donate my help...
Quote Reply
Re: [webmaster33] Question only for experts. In reply to
Guys, I certanly appreaciate all the effort. But my code works in listing the correct categories in the correct order. if you read my post the problem I'm having is with the sort of the fields at the end. This global is really usefull for those of you who would like to have links of different types in the same directory (you need to add a field and modify Links SQL of course) but at the global will be really usefull because it will let you add records only on those categories that contain records of the type you are adding.

Look at the assosiative array called %res the problem I have is sorting it. i don't want to sort IDENT fields because they serve only to ident (space) Subcategories from main categories.

By the way, Paul.. are you the developer of the time Plugin? if so how did you solve the error results when used in conjuction with search cache plugin?
Quote Reply
Re: [jaltuve] Question only for experts. In reply to
Here's the (a bit) cleaned code:
Code:
sub {
#################################################################
# SHOW ONLY CATEGORIES THAT CONTAIN LINKS OF TYPE $LinkType #
#################################################################
my $onlyroot = 0; # set to 1 for displaying root categories only
my $mult = 1; # Number of columns
my $margin = " >>>> ";
###############################################################
my ($rec) = @_;
my $LinkType = $rec->{LinkType} || 'Regular';
my ($name,$id,$category,$ident);
my $db = $DB->table('Category');
my $self = $DB->html($db, $IN);
$db->select_options ( 'ORDER BY Full_Name');
my $sth = $db->select ( ['ID', 'Full_Name', 'FatherID'] );
my $cat_link = $DB->table('CatLinks', 'Links', 'Category');
my %res = ();

while (my ($id, $name, $tags) = $sth->fetchrow_array) {
# ~ ~ ~ replace this code to similar solution I recommended in post #4 - BEGIN ~ ~ ~
my $child_total = $cat_link->count(GT::SQL::Condition->new(
['Full_Name', 'LIKE', "$name/%"], ['isValidated', '=', 'Yes'], ['LinkType', '=', "$LinkType"]
));
my $root_total = $cat_link->count({ LinkType => $LinkType, isValidated => 'Yes',
'Links.ID' => $id });
my $total_acum = ($child_total + $root_total);
$ident = "";

if ($tags == 0) {$ident = "$margin"}
if ($onlyroot == 1) {
if (($total_acum > 0) && ($tags == 0)) {
$res{$id} = "$ident $name";
}
} else {
if ($total_acum > 0) {
$res{$id} = "$ident $name";
}
}
}
# ~ ~ ~ replace this code to similar solution I recommended in post #4 - END ~ ~ ~
return $self->select ( { name => $name, values => \%res, value => $id, multiple => $mult ,
sort => sub { lc $_[0] cmp lc $_[1] } } );
}

1) The code was very unreadable, so I made the it readable. Reposted here (only added ordering into query, and removed %sortby hash)

2) The ordering you can do right in the sql query. I added to the code above.

3) Then you can use the solution or a similar solution what we discussed with Paul.
I deleted the %sortby hash, since it's unnecessary...
Also the code within the while is also unnecessary. At least I would do it other way. You may replace it with the suggested code.
Of course you don't need to use my code I gave you in post #4, but it's a good startpoint what to do.

4) If you do not want multi level indenting, just 1 level indenting (as I saw this is what you want), then the task is much easier. You just also get the FatherID from Category table, then indent 1x all names, which does not have FatherID = 0.
It's that simple.

I hope this helps you to finish the job, based on the suggestions and the example I gave.
Work out the solution yourself, then we will help you in further optimizations if needed.

Best regards,
Webmaster33


Paid Support
from Webmaster33. Expert in Perl programming & Gossamer Threads applications. (click here for prices)
Webmaster33's products (upd.2004.09.26) | Private message | Contact me | Was my post helpful? Donate my help...