Jump to content

How to add multiple page references through api?


Recommended Posts

Posted

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.

Posted

The syntax in your second example is correct. When you say it didn't work, can you describe further? Was there an error message?

Posted

If you want, feel free to email me the script and I can track it down more easily being able to see it all.

Posted

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?

Posted

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");
...
Posted

Thanks Ryan. I will change my selectors to name, I think it is cleaner in many ways.

I don't know if it's good idea to code while being ill (common cold). I mean my script is a monster :)

Posted

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. :)

Posted

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();

Posted

Original title is: PROJECT DECAY (NOR) w/ VIISIKKO & FLESHPRESS-1751059

It must be / or & doing bad things here?

Posted

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?

Posted

It is there, but shouldn't this do update in this case?

I try to look if the page is already there, if not, then create new page, else update info & save.

Posted

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...

Posted

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.

Posted

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();
}
Posted

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)!

Posted

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'
Posted

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.

Posted

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" :)

Posted

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.

Posted

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.

Posted

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?)

Posted

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!

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
  • Recently Browsing   0 members

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