Jump to content

How to add multiple page references through api?


apeisa
 Share

Recommended Posts

I have page field called "supporters" and it allows multiple pages. How I add multiple pages through API?

Usually this is done like this:

$gig->supporters = $page;

This of course doesn't work with multiple pages. I tried this (found from current docs, used in images):

$gig->supporters->add($page);

But it doesn't work.

Link to comment
Share on other sites

It works now.

I am creating cron script that get's gig information from last.fm api. Problem was that I checked if I already have current support artist in database, if not, create new one. Also add new page to $supporter_pages array so I can later add it to related gig. This last part (adding to array) was only done when creating new pages, not if I already had it in database.

if (count($wire->pages->find('template=artist, title="'.$supporter.'"'))) {
 $support = $wire->pages->find('template=artist, title="'.$supporter.'"');
 $supporter_pages[] = $support; // <-- THIS WAS MISSING
} else {
 $support = new Page();
 ....

Those selectors aren't probably best ones (title), I think it should be better to use $get and url? Is get faster?

Link to comment
Share on other sites

For something like this, I usually prefer to use the name field over the title field just because there's no worry about escaping quotes, whitespace, etc. But if your $supporter is never going to have double quotes in it, then you are probably fine to use title. Speed wise, I don't think you are paying any penalty by using the title--it should have a full index in the DB, which will keep it just as fast as name. However, I do think you could improve this by only doing one call to $pages->find(). In addition, yo should probably use $pages->get() rather than $pages->find() since your $supporter_pages[] = $support seems to assume that $support is a Page rather than a PageArray. Here is what I would change it to:

<?php
$support = $wire->pages->get('template=artist, title="' . $supporter . '"');
if($support->id) {
    $supporter_pages[] = $support; 
} else {
    $support = new Page();
    ...
}

If you want to use the name field instead of the title field (though it may not be necessary), you could do this:

<?php
$name = $wire->sanitizer->pageName($supporter); 
$support = $wire->pages->get("template=artist, name=$name");
...
Link to comment
Share on other sites

Using name may be better just because it can only consist of these ascii characters: -_.a-z0-9. Meaning it's easy to validate, and easy to use as a urlSegment or GET variable. If all of your artists are in one dir, then you can also change your selector to:

$support = $wire->pages->get("/artists/$name/"); 

There may not necessarily be any advantage to doing that over what you were doing, but it's just an alternate approach.

Nothing wrong with coding while ill, just drink Dayquil rather than Nyquil (I speak from experience). :) (if they have that cold medicine in Finland?). Or better yet, coffee, or both. :)

Link to comment
Share on other sites

Thanks. I have something that my wife calls "ällöjuoma" -> "ugly drink" to support me :)

I changed all to use name. It seems to work well mostly, but it gives me this error in one event. Only difference I can think of is that this name is rather long..

Uncaught exception 'WireDatabaseException' with message 'Duplicate entry 'project-decay-nor-w-viisikko-fleshpress-1751059-6984' for key 'name_parent_id'' in /srv/www/keikalle.com/public_html/wire/core/Database.php:72
Stack trace:
#0 /srv/www/keikalle.com/public_html/wire/core/Pages.php(355): Database->query('INSERT INTO pag...')
#1 [internal function]: Pages->___save(Object(Page))
#2 /srv/www/keikalle.com/public_html/wire/core/Wire.php(241): call_user_func_array(Array, Array)
#3 /srv/www/keikalle.com/public_html/wire/core/Wire.php(203): Wire->runHooks('save', Array)
#4 [internal function]: Wire->__call('save', Array)
#5 /srv/www/keikalle.com/public_html/wire/core/Page.php(733): Pages->save(Object(Page))
#6 /srv/www/keikalle.com/cron/query_lastfm.sh(172): Page->save()
#7 /srv/www/keikalle.com/cron/query_lastfm.sh(6): get_data(1, Object(ProcessWire))
#8 {main}
  thrown (line 72 of /srv/www/keikalle.com/public_html/wire/core/Database.php)

This error message was shown because you are logged in as a Superuser.

Here is some of my code:

$gigName = $event['title'] . '-' . $event['id'];
$gigNameUrl = $wire->sanitizer->pageName($gigName);
$gig = $wire->pages->get("template=gig, name=$gigNameUrl");

if ($gig->id) {
echo $gig->title . ": gig is already in database, we only update \n";
} else {
$gig = new Page();
$gig->template = 'gig';
$gig->parent = $gig_parent;
}

$gig->title = $event['title']; // We dont use $gigName here because we don't want last.fm id to title
$gig->datetime = $event['startDate'];
$gig->venue = $venue;
$gig->lastfmid = $event['id'];
$gig->headliner = $head;

foreach($supporter_pages as $supporter) {
$gig->supporters->add($supporter);
}

unset($supporter_pages);

$gig->name = $gigNameUrl; // Here we want to use gigNameUrl since there is also last.fm id (there are same names for different gigs)

$gig->save();

Link to comment
Share on other sites

Actually this is a duplicate entry error. I've setup MySQL to maintain a unique index between the page name and the parent_id, so that it's impossible to have two pages with the same name under the same parent. So the error you got here is from MySQL telling you that you are attempting to insert a page with the same name as one that's already there. Can you check if a page named "project-decay-nor-w-viisikko-fleshpress-1751059" is already there?

Link to comment
Share on other sites

Here is the problematic part of the code:

$gigName = $event['title'] . '-' . $event['id'];
$gigNameUrl = $wire->sanitizer->pageName($gigName);
$gig = $wire->pages->get("template=gig, name=$gigNameUrl");

if ($gig->id) {
echo $gig->title . ": gig is already in database, we only update \n";
} else {
$gig = new Page();
$gig->template = 'gig';
$gig->parent = $gig_parent;
}

... update values ...

$gig->name = $gigNameUrl;

$gig->save()

It works on other events, but for some reason not for this one... Somehow if($gig->id) returns false, but then I set the exact same value ($gigNameUrl) as name and still duplicate...

Link to comment
Share on other sites

I think I might know what the deal is. Try changing this line:

$gigNameUrl = $wire->sanitizer->pageName($gigName);

To this:

$gigNameUrl = $wire->sanitizer->pageName($gigName, true);

The second param "true", tells it to beautify (remove doubled chars and stuff). I forgot that the Page class uses that beautify option, so adding the "true" will ensure it's consistent in how it generates the page name. I bet this will fix the problem.

Link to comment
Share on other sites

I commented $gig->save() on this one and tested rest of the script. Similar situation also fails on artist called: Super8 & Tab. There is also ampersand, so it is probably the reason. It get's manipulated in some point - probably on db save.

This is the code that fails when $supporter = "Super8 & Tab"

$supporterNameUrl = $wire->sanitizer->pageName($supporter);
$support = $wire->pages->get("template=artist, name=$supporterNameUrl");
if (!$support->id) {
$support = new Page();

$support->template = 'artist';
$support->parent = $artist_parent;

$support->title = $supporter;
$support->name = $supporterNameUrl;

$support->save();
}
Link to comment
Share on other sites

I think I might know what the deal is. Try changing this line:

$gigNameUrl = $wire->sanitizer->pageName($gigName);

To this:

$gigNameUrl = $wire->sanitizer->pageName($gigName, true);

The second param "true", tells it to beautify (remove doubled chars and stuff). I forgot that the Page class uses that beautify option, so adding the "true" will ensure it's consistent in how it generates the page name. I bet this will fix the problem.

You bet right, it works like a dream. Thank you (again) very much!

You will be first person to play with our app when we get it ready. It is gonna be supersweet (mobile html5 app)!

Link to comment
Share on other sites

Hah, I got one more problem. Though I fully understand why (but I don't know best way to handle it yet...).

I have artist called: ギルガメッシュ

So after sanitizer it goes very nice: (this space intentionally left empty)

And saving currently gives error:

Uncaught exception 'WireException' with message 'Can't save page 0: /artisti/0/: It has an empty 'name' field'
Link to comment
Share on other sites

Wow, good question. It looks like PHP iconv has no equivalent conversion to ascii for those characters (understandable). Are there any other properties to that artist that could be used as a name... for instance their last.fm id or something like that? The "name" field can be anything, it doesn't necessarily have to be related to the title. If the ID numbers you are getting out of last FM are unique per artist, then it may be best just to use those... that would solve these cases of titles that are not translatable to ascii.

Link to comment
Share on other sites

My first idea was this:

if ($headlinerNameUrl == '') {
$headlinerNameUrl = $wire->sanitizer->pageName(urlencode($headlinerName), true);
}

And it gives us nice url: e3-82-ae-e3-83-ab-e3-82-ac-e3-83-a1-e3-83-83-e3-82-b7-e3-83-a5 :)

I'll live with that now, since it really doesn't matter in this point. There probably could be something much nicer for this one, but this is "rock solid" :)

Link to comment
Share on other sites

The "name" field can be anything, it doesn't necessarily have to be related to the title. If the ID numbers you are getting out of last FM are unique per artist, then it may be best just to use those...

There is artist id also from last.fm, but I am only querying events (and it only gives artist name, id:s only for events). So that would require another request from last.fm api.

Link to comment
Share on other sites

I think you've got the right approach there, checking to see if pageName returned something blank. Very creative to use urlencode here. :) Using that same approach, you could also try md5($headlinerName) rather than (or in addition to) urlencode() as a shorter option... it will always be 32 characters regardless of the title's length.

Link to comment
Share on other sites

There is artist id also from last.fm, but I am only querying events (and it only gives artist name, id:s only for events). So that would require another request from last.fm api.

Is there any possibility that two different artists will have the same name? (with different IDs at last.fm?)

Link to comment
Share on other sites

Universally there are many bands with the same name. I'm not sure how Last.fm API handles those - their site usually outputs country in parenthesis in case of duplicates (or more). I am not worried about those: in our case it doesn't really matter that much.

Good idea with md5. It will be cleaner for sure!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...