Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand the taxonomy support with methods to search/load terms at store level #892

Closed
jansenbe opened this issue Jun 23, 2022 · 17 comments
Closed
Labels
area: model 📐 Related to the core SDK models

Comments

@jansenbe
Copy link
Contributor

From @gzdev in #849:

Support for new TermStore Rest API _api/v2.1/termStore (used in ModernExperience).

For example: CSOM (Microsoft.SharePoint.Client) offers a way to search for Terms using the one of the following methods:

  • Microsoft.SharePoint.Client.Taxonomy.TermStore.GetTerms(LabelMatchInformation labelMatchInformation)
    RestApi EndPoint: {SiteUrl}/_api/v2.1/termStore/searchTerm(label='{WordsToSearchFor}',languageTag='en-US')?$expand=set
    PnP JS has already implemented the searchTerm method (Link to PnP JS GitHub Report -> searchTerm docs)

  • Microsoft.SharePoint.Client.Taxonomy.TermStore.GetTermsById(Guid[] termIds)
    Get multiple Terms by Id without loading the FieldInfo to get the TermSet.Id to get the TermSet and then getting each Term by Id, ...
    I don't know wether there is any RestApi EndPoint to offer such a way to get multiple terms at once.

  • Also a way getting a term (GetTermById) without knowing the term group would be nice.

Is there a way to get these features in PnP Core SDK?

Btw do anyone know where the documentation of _api/v2.1/termStore clould be found?

Response:

@gszdev , thanks for the feedback, these indeed are useful extensions to have. We're using Microsoft Graph for taxonomy support , will need to check if this is possible using Graph. Using the v2.1 endpoint is not something we support today and (theoretically) this end point is the SharePoint proxy for Graph and one should prefer using Graph over v2.1 whenever possible.

For getting multiple terms in one go batching might be the solution, will investigate that as well.

Update: quick research showed that both requests are not possible today using Microsoft Graph. I'll check with the Graph team owning these features, plan B could be to wrap the CSOM endpoints (like we do for some other missing methods). I'll create a separate issue to track this request.

@gszdev
Copy link

gszdev commented Jun 23, 2022

Also a way getting a termset (GetTermSetById) without knowing the term group would be nice.

@jansenbe
Copy link
Contributor Author

From @gszdev:

Moving the TaxonomyExtensions.GetWssIdForTerm from PnP Framework to PnP Core SDK would also be helpfull.

Here's the link to the PnP Framework (CSOM) implementation:
TaxonomyExtensions.GetWssIdForTerm

I'm new to PnP Core SDK so I'm not able to create a pull request because I don't know where how to put the methods in (IWeb, ITermStore, ...).

Here's my code snipped (Extension Methods) for PnPCore SDK:
`

public static class SharePointIWebExtensions
{
	public static int GetWssIdForTerm(this IWeb web, ITerm term)
	{
		return GetWssIdForTermAsync(web, term.Id).GetAwaiter().GetResult();
	}

	public static int GetWssIdForTerm(this IWeb web, Guid termId)
	{
		return GetWssIdForTermAsync(web, termId.ToString()).GetAwaiter().GetResult();
	}

	public static int GetWssIdForTerm(this IWeb web, string termId)
	{
		return GetWssIdForTermAsync(web, termId).GetAwaiter().GetResult();
	}

	public static async Task<int> GetWssIdForTermAsync(this IWeb web, ITerm term)
	{
		return await GetWssIdForTermAsync(web, term.Id).ConfigureAwait(false);
	}

	public static async Task<int> GetWssIdForTermAsync(this IWeb web, Guid termId)
	{
		return await GetWssIdForTermAsync(web, termId.ToString()).ConfigureAwait(false);
	}

	public static async Task<int> GetWssIdForTermAsync(this IWeb web, string termId)
	{
		var site = web.PnPContext.Site;
		var taxonomyHiddenListServerRelativeUri = UrlUtility.Combine(site.ServerRelativeUrl, "Lists/TaxonomyHiddenList");

		var taxonomyHiddenList = await site.RootWeb.Lists.GetByServerRelativeUrlAsync(taxonomyHiddenListServerRelativeUri.ToString());

		var camlQuery = new CamlQueryOptions()
		{
			ViewXml = $@"<View><Query><Where><Eq><FieldRef Name='IdForTerm' /><Value Type='Text'>{termId}</Value></Eq></Where></Query></View>",
			DatesInUtc = true,
		};                        

		await taxonomyHiddenList.LoadItemsByCamlQueryAsync(camlQuery);
		var items = taxonomyHiddenList.Items.AsRequested();

		if (items.Any())
		{
			return items.First().Id;
		}
		else
		{
			return -1;
		}
	}
}

`

@jansenbe
Copy link
Contributor Author

@gszdev : as mentioned above needed Graph APIs currently are not present, but they've been added to the respective team's backlog

jansenbe added a commit that referenced this issue Jun 28, 2022
…ing a termset without knowing the termset group #892
jansenbe added a commit that referenced this issue Jun 28, 2022
… to enable loading a termset or term without knowing the termset group #892
@jansenbe
Copy link
Contributor Author

jansenbe commented Jun 28, 2022

@gszdev : I've added methods on ITermStore that allow you to get a termset by id or a term by id if you also have the termset id (see https://github.com/pnp/pnpcore/blob/dev/src/sdk/PnP.Core/Model/SharePoint/Taxonomy/Public/ITermStore.cs#L43-L151). These methods also support batching, so you can create a batch that loads multiple termsets / terms in a single go. You do need to know the termset id when loading a term in this manner, for that it's recommended to load the (list) fields once and get the needed termset id from there.

What's still missing is loading a term with just knowing it's id or searching for a term based upon it's label, currently there's no graph method that directly can get a term from the termstore without knowing the termset.

@jansenbe
Copy link
Contributor Author

jansenbe commented Jun 28, 2022

Also a way getting a termset (GetTermSetById) without knowing the term group would be nice.

and

Also a way getting a term (GetTermById) without knowing the term group would be nice.

This is possible now, see previous comment

@gszdev
Copy link

gszdev commented Jun 28, 2022

Thank you very much.
I assume I need nighly build. So I'll have to wait till tomorrow. ;-)

@jansenbe
Copy link
Contributor Author

@gszdev : yes, the new methods will appear in the nightly build and will be part of the 1.7 release coming this week.

I've also just added GetWssIdForTerm methods on IWeb: see https://github.com/pnp/pnpcore/blob/dev/src/sdk/PnP.Core/Model/SharePoint/Core/Internal/Web.cs#L1898-L1928

@Nevinia210
Copy link

Hi,
will there be also some support for getting parent of term? currently in 1.6.92-nightly there is option for Term.Parent, but it return collection instead of single term and in that collection are all terms in whole set

@jansenbe
Copy link
Contributor Author

@Nevinia210 : Can you check Term.Parent.Parent...Parent can be term collection, but the parent of the termcollection can be another term

@Nevinia210
Copy link

Nevinia210 commented Jun 29, 2022

@jansenbe
it seems like Term.Parent.Parent is TermSet
image

@jansenbe
Copy link
Contributor Author

jansenbe commented Jun 29, 2022

@Nevinia210 : Is your Term a child of another Term?

@Nevinia210
Copy link

@jansenbe : yes, its Level3 in this case:
image

@jansenbe
Copy link
Contributor Author

@Nevinia210 : think this is due to way you load the term then? In my test case (see here). Breakpoint was on line 972.

image

@Nevinia210
Copy link

@jansenbe : i tried your approach with loading terms but still not success, am i missing something?

var siteMapTermSet = pnpContext.TermStore.GetTermSetById(selectedTermSetId.ToString());
await siteMapTermSet.LoadAsync(p => p.Terms);
var selectedTerm = siteMapTermSet.Terms.GetById(taxField.TermId.ToString());
await selectedTerm.LoadAsync(x => x.Terms);
var test = (ITerm)selectedTerm.Parent; // System.InvalidCastException: 'Unable to cast object of type 'PnP.Core.Model.SharePoint.TermCollection' to type 'PnP.Core.Model.SharePoint.ITerm'.'
var test2 = (ITerm)selectedTerm.Parent.Parent;// System.InvalidCastException: 'Unable to cast object of type 'PnP.Core.Model.SharePoint.TermSet' to type 'PnP.Core.Model.SharePoint.ITerm'.'

@jansenbe
Copy link
Contributor Author

@Nevinia210 : this will not work in that way, the Parent model is built based upon a step by step loading of model instances, if you directly load a given term then there's no full parent tree available. Probably easiest for now is loading the termset and then iterating over the terms...The Graph API has not support to directly load the parent term of a term, so no easy way out of this if you're no enumerating the whole termset

@jansenbe
Copy link
Contributor Author

@gszdev / @Nevinia210 : I'll close this issue as we're currently using all the possible taxonomy Graph APIs. There most likely will be additional API later this year and once they ship, we'll integrate them in PnP Core SDK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: model 📐 Related to the core SDK models
Projects
None yet
Development

No branches or pull requests

3 participants