Jump to content

remove entry from pagesfield via api


martind
 Share

Recommended Posts

$page->[field-name]->remove($[page-you-want-to-remove]); 
$page->save();

For example, if you wanted to remove the first page:

$p = $page->related_pages->first(); 
$page->related_pages->remove($p);
$page->save(); 
Link to comment
Share on other sites

thanks, got it.

$p = $wire->pages->get($p_get); // page to add/remove into pagefield

$user->of(false);
foreach($user->abos AS $abo){
 if($abo->id == $p->id){
  $user->abos->remove($p);
 }else{
  $user->abos = $p;
 }
}
$user->save();

..is there a more elegant possibility to check against existing entries in the page-field?

Link to comment
Share on other sites

..is there a more elegant possibility to check against existing entries in the page-field?

Yes there is, method has(). Assuming you're trying to remove a page from a page field if it is there already and otherwise add it there:

if($user->abos->has($p)) {
   $user->abos->remove($p);
} else {
   $user->abos->add($p);
}

Notice also that $user->abos is a PageArray while $p is a Page, so plain assign wont work. You'd have to use add() method as in my example above.

  • Like 1
Link to comment
Share on other sites

Looks like you're right martind, sorry for the confusion.

At least I got confused with this, so let's make things clear in case someone else stumbled across this sometime later:

When dealing with FieldtypePage (a field of type Page in Setup -> Fields), it's ok to assign a single Page object to the field and things just work. If the field is set to be dereferenced as PageArray (edit the field -> details), the assigned page is added to the array. Otherwise the given Page object is naturally assigned to the field (field is set to be dereferenced as Page).

On the other hand (this is what got me confused in the first place), when dealing with plain PageArray simple assign of a Page does not work, but add() method has to be used. It's the FieldtypePage that adds the magic.

While it's great to have such convenience added here and there, one would expect things to work the same way where applicable. At least I would. :) This is actually why I was so keen on making sort, start and limit with WireArrays work more like they work when using selectors. I think there are some other cases as well where this kind of alignment could be a good thing.

  • Like 2
Link to comment
Share on other sites

When dealing with FieldtypePage (a field of type Page in Setup -> Fields), it's ok to assign a single Page object to the field and things just work.

FieldtypePage will take a whole lot of different things: integers, strings, multiple IDs encoded in strings, arrays, a Page, a PageArray, etc. But the point here is so that it can accommodate various export/import and data abstraction situations.

As an example, lets say you export a bunch of pages to a CSV file and one field has multiple page references (lets call it 'pagerefs'). The page references become a string like "123|456|789" in the CSV. When that CSV gets imported again, $page->pagerefs gets assigned the string value of "123|456|789" and it needs to be smart enough to know what to do with that.

In ProcessWire, any page field can be represented in a more basic type like this. This is what enables a high amount of portability with the data for export/import and web service situations. But that doesn't mean it's recommended API usage. For API usage, you should treat it as the type you specified in the field settings, be that a PageArray or a Page.

While it's great to have such convenience added here and there, one would expect things to work the same way where applicable. At least I would.

I'm not aware of anywhere else that this type of overloading would be possible. I also don't want to recommend these abstractions for regular API usage. This is purely for the benefit of behind-the-scenes portability and automation. I don't think it's so applicable outside of the context of a $page->set() situation.

  • Like 2
Link to comment
Share on other sites

Makes sense, must agree on everything you're saying.

In ProcessWire, any page field can be represented in a more basic type like this. This is what enables a high amount of portability with the data for export/import and web service situations. But that doesn't mean it's recommended API usage. For API usage, you should treat it as the type you specified in the field settings, be that a PageArray or a Page.

ProcessWire really is great with export/import like you've intended. It's kind of a side effect that some a bit unusual things work. My habit of reading the source code doesn't always (usually even) lead to right conclusions and it would probably be better not to say everything aloud. Maybe I should just start using Soma's cheatsheet more instead of that. :)

I was just surprised to see that assign really works that way there as I never would've tried that out myself.

I'm not aware of anywhere else that this type of overloading would be possible. I also don't want to recommend these abstractions for regular API usage. This is purely for the benefit of behind-the-scenes portability and automation. I don't think it's so applicable outside of the context of a $page->set() situation.

Couldn't agree more on this now that I understand it wasn't for convenience but for something totally different. Still, it would be great if there was a way to check which features aren't supposed to be used via API but are reserved for internal use. Then it would be 'at your own risk' to use something like that.

Or is it actually so that the cheatsheet tries to cover more or less everything that is safe and recommended to use? As I said before, I haven't used that enough, clearly. I'm trying to follow recommendations myself whenever possible, but it isn't always clear where to find the recommendation (other than asking here, but somehow I'm not so used to doing that every time, yet).

Documenting internal methods and usages in the comments has been also discussed before and that's a good way to achieve what I'm after here. It doesn't make things clear to someone who just happens to try some syntax that's not meant to be used - but what does, apart from disabling things somehow (no, I'm not suggesting that at all).

This is enough for now, I think. ProcessWire works great and is great, and will be surprising me every now and then for a very long time. And I'm very happy with the way things are even if I may whine a little sometimes.

  • Like 1
Link to comment
Share on other sites

Still, it would be great if there was a way to check which features aren't supposed to be used via API but are reserved for internal use. Then it would be 'at your own risk' to use something like that.

Given that we don't know what the user's fields or types will be ahead of time, there isn't really any way to document it with the Page class (that I know of). The function that handles this particular situation (setting a value to a $page->pageref) is FieldtypePage::sanitizeValue(). It is currently documented (with phpdoc) to indicate what it's for and all the values that it accepts and returns. But doesn't say anything like "usually you'd set a PageArray" because I don't think anyone is going to be looking here unless they already know the routes that setting a value to a Page takes. Ultimately, the best way to document this sort of stuff may be outside of the code itself and in online documentation specific to each Fieldtype.

Or is it actually so that the cheatsheet tries to cover more or less everything that is safe and recommended to use?

I think the cheatsheet is a great resource for this stuff. Though I don't think there's anything specific to the situation we're talking about just because it's one of those things specific to a FieldtypePage. So I think FieldtypePage probably needs it's own manual. :)

Documenting internal methods and usages in the comments has been also discussed before and that's a good way to achieve what I'm after here.

That's what we're doing now. But I'm not sure how to communicate to someone that when they set (or get) a value to a Page, a lot of decisions go on behind the scenes. In our particular case of setting a $page->pageref, the path would be this (pseudocode):

$page->set('field_name', $somePage); {
 // if 'field_name' is a custom field confirmed by the page's fieldgroup, use setFieldValue()
 $this->setFieldValue('field_name', $somePage); {
   // get the Field object
   $field = $this->fields->get('field_name'); 
   // let the Fieldtype sanitize the value before setting it to the $page, i.e. convert Page|int|string|array to PageArray
   $value = $field->type->sanitizeValue($this, $field, $somePage); 
 }
}

That last line is where the magic happens. The sanitizeValue will accept $somePage in various types, but always returns a PageArray back to the page. If it gets something it doesn't like, then it's either going to throw an Exception or refuse it (depending on what the Fieldtype author thinks is appropriate).

Something similar happens when you get() a value from a Page, tough even more behind the scenes:

$page->get('field_name'); {
 // if field_name is a custom field confirmed by the page's fieldgroup, use getFieldValue()
 $this->getFieldValue('field_name'); {
   $field = $this->fields->get('field_name');
   $value = parent::get('field_name'); // check if it's already loaded
   if(is_null($value)) { 
     // value isn't yet loaded, so load it
     $value = $field->type->loadPageField($this, $field); 
     if(is_null($value)) {
       // if no value then set a default (like blank PageArray)
       $value = $field->type->getDefaultValue($this, $field); 
     } else {
       // convert value to runtime type, like array of ints => PageArray of Pages
       $value = $field->type->wakeupValue($this, $field, $value);
     }
   }
   // if output formatting is on, let the fieldtype modify it for presentation (if it wants to)
   if($this->outputFormatting) $value = $field->type->formatValue($this, $field, $value); 
 }
}

I'm not exactly sure how to document this beyond the pseudocode above, or if it even matters. I'd rather people think of it as just setting or getting values and everything works. :) But it seems like a separate page of documentation for each Fieldtype might help to answer some of the questions.

  • Like 2
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...