Skip to content

N°9687 - Fix incorrect return type for the DBObjectSearch::ApplyDataFilter() function#939

Open
Molkobain wants to merge 4 commits into
support/3.2.3from
issue/9687-fix-incorrect-return-type-for-the-dbobjectsearch-applydatafilter-function
Open

N°9687 - Fix incorrect return type for the DBObjectSearch::ApplyDataFilter() function#939
Molkobain wants to merge 4 commits into
support/3.2.3from
issue/9687-fix-incorrect-return-type-for-the-dbobjectsearch-applydatafilter-function

Conversation

@Molkobain

@Molkobain Molkobain commented Jun 17, 2026

Copy link
Copy Markdown
Member

Base information

Question Answer
Related to a SourceForge thread / Another PR / A GitHub Issue / Combodo ticket? N°9687
Type of change? Bug fix

Symptom (bug)

Fatal error when accessing the backoffice with a non-admin user.

2026-06-15 09:54:55 | Error   | 3     | Uncaught TypeError: DBObjectSearch::ApplyDataFilters(): Return value must be of type DBObjectSearch, DBUnionSearch returned in /var/www/php8.1/pro322-1/core/dbobjectsearch.class.php:1960
Stack trace:
#0 /var/www/php8.1/pro322-1/core/dbsearch.class.php(1125): DBObjectSearch->ApplyDataFilters()
#1 /var/www/php8.1/pro322-1/core/dbsearch.class.php(1039): DBSearch->GetSQLQuery()
#2 /var/www/php8.1/pro322-1/core/metamodel.class.php(6181): DBSearch->MakeSelectQuery()
#3 /var/www/php8.1/pro322-1/core/metamodel.class.php(6368): MetaModel::MakeSingleRow()
#4 /var/www/php8.1/pro322-1/core/metamodel.class.php(6281): MetaModel::GetObjectWithArchive()
#5 /var/www/php8.1/pro322-1/core/userrights.class.inc.php(334): MetaModel::GetObject()
#6 /var/www/php8.1/pro322-1/core/userrights.class.inc.php(1336): User->GetContactObject()
#7 /var/www/php8.1/pro322-1/core/userrights.class.inc.php(1280): UserRights::GetContactObject()
#8 /var/www/php8.1/pro322-1/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenu.php(476): UserRights::GetContactOrganizationFriendlyname()
#9 /var/www/php8.1/pro322-1/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenu.php(130): Combodo\iTop\Application\UI\Base\Layout\NavigationMenu\NavigationMenu->ComputeUserData()
#10 /var/www/php8.1/pro322-1/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenuFactory.php(59): Combodo\iTop\Application\UI\Base\Layout\NavigationMenu\NavigationMenu->__construct()
#11 /var/www/php8.1/pro322-1/sources/Application/WebPage/iTopWebPage.php(149): Combodo\iTop\Application\UI\Base\Layout\NavigationMenu\NavigationMenuFactory::MakeStandard()
#12 /var/www/php8.1/pro322-1/pages/UI.php(267): Combodo\iTop\Application\WebPage\iTopWebPage->__construct()
#13 {main}
 thrown | IssueLog |||
array (
 'type' => 1,
 'file' => '/var/www/php8.1/pro322-1/core/dbobjectsearch.class.php',
 'line' => 1960,
)

Reproduction procedure (bug)

  1. On iTop 3.2.3-1
  2. The XML delta below
  3. A user with Support agent profile and allowed organizations
  4. Log in the backoffice
  5. Try to create a ticket

Cause (bug)

Fix a fatal type mismatch in data filtering when user rights filters return a union search.

DBObjectSearch::ApplyDataFilters() is currently typed to return DBObjectSearch, but in some valid scenarios (custom rights profile / team silos), filters return DBUnionSearch.
This causes a runtime TypeError and breaks login, impersonation, and some non-admin actions (for example ticket creation).

Proposed solution (bug and enhancement)

The fix is to broaden the return type from DBObjectSearch to DBSearch, which matches actual behavior and accepted filter outputs.

Checklist before requesting a review

  • I have performed a self-review of my code
  • I have tested all changes I made on an iTop instance
  • I have added a unit test, otherwise I have explained why I couldn't
  • Is the PR clear and detailed enough so anyone can understand without digging in the code?

@Molkobain Molkobain self-assigned this Jun 17, 2026
@Molkobain Molkobain added the bug Something isn't working label Jun 17, 2026
@Molkobain Molkobain added this to the 3.2.3-2 milestone Jun 17, 2026
@Molkobain

Copy link
Copy Markdown
Member Author

Draft until unit tests are pushed

@Molkobain

Copy link
Copy Markdown
Member Author

@greptileai review please

@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR broadens data-filter search return types to handle union filters. The main changes are:

  • DBObjectSearch::ApplyDataFilters() now returns the base DBSearch type.
  • DBUnionSearch::ApplyDataFilters() now matches the same base return type.
  • A regression test covers a user-rights filter returning DBUnionSearch.
  • The test fixture provides a custom GetSelectFilter() implementation for the union-filter case.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
core/dbobjectsearch.class.php Return type now matches the existing DBSearch abstraction used by callers.
core/dbunionsearch.class.php Return type now stays compatible with recursive filter application.
tests/php-unit-tests/unitary-tests/core/DBSearch/DBSearchApplyDataFiltersTest.php Regression coverage exercises a user-rights filter that returns a union search and restores the selected module afterward.

Reviews (4): Last reviewed commit: "N°9687 - Improve unit test after code re..." | Re-trigger Greptile

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a fatal PHP TypeError caused by DBObjectSearch::ApplyDataFilters() being declared to return DBObjectSearch while it can legitimately return a DBUnionSearch (eg. when user rights filters produce union searches). The change aligns method signatures with actual runtime behavior by using the common base type DBSearch.

Changes:

  • Broadened ApplyDataFilters() return type in DBObjectSearch from DBObjectSearch to DBSearch to prevent runtime return type violations.
  • Broadened ApplyDataFilters() return type in DBUnionSearch from DBUnionSearch to DBSearch for consistency and to accommodate parent::ApplyDataFilters() behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
core/dbobjectsearch.class.php Updates ApplyDataFilters() return type to DBSearch to avoid TypeError when filtering returns a DBUnionSearch.
core/dbunionsearch.class.php Updates ApplyDataFilters() return type to DBSearch, matching the base contract and supporting delegation to parent::ApplyDataFilters().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Molkobain Molkobain marked this pull request as ready for review June 18, 2026 10:02
protected function ApplyDataFilters(): DBObjectSearch
protected function ApplyDataFilters(): DBSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsDataFiltered() is doing the opposite of what the name seems to tell... hard to understand at first sight.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly advice to complete PHPDOC of all used methods... some are missing or incomplete (mixed).

ie GetSearches, FromEmptySet, GetSelectedClasses, GetJoinedClasses.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apart from that if we do the minimum to change the code, it could be nice to have full test cover of 3 distincts kinds of ApplyDataFilters (DBUnionSearch, DBsearch, DBObjSearch().

for example security.disable_joined_classes_filter in the conf can change the behaviour. just as UserRightsGetSelectFilter extensibility.... we can discuss it if you want

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last but not least it could be nice to refactor in one common method. where we would pass an array of string (coming from either GetSearches, GetSelectedClasses or GetJoinedClasses).

		// Apply filter (this is similar to the one in DBSearch but the factorization could make it less readable)
		foreach ($aClassesToFilter as $sClassAlias => $sClass) {
			$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
			if ($oVisibleObjects === false) {
				$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
			}
			if (is_object($oVisibleObjects)) {
				$oVisibleObjects->AllowAllData();
				$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
				$oSearch->SetDataFiltered();
			}
		}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to compute GetSelectedClass if 'security.disable_joined_classes_filter' is disabled.

@odain-cbd odain-cbd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should discuss... my guess is that we will focus on the minimum. which is not 100% sure from what i see in the code. i understand that i dont understand everything....

protected function ApplyDataFilters(): DBObjectSearch
protected function ApplyDataFilters(): DBSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly advice to complete PHPDOC of all used methods... some are missing or incomplete (mixed).

ie GetSearches, FromEmptySet, GetSelectedClasses, GetJoinedClasses.

protected function ApplyDataFilters(): DBObjectSearch
protected function ApplyDataFilters(): DBSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apart from that if we do the minimum to change the code, it could be nice to have full test cover of 3 distincts kinds of ApplyDataFilters (DBUnionSearch, DBsearch, DBObjSearch().

for example security.disable_joined_classes_filter in the conf can change the behaviour. just as UserRightsGetSelectFilter extensibility.... we can discuss it if you want

protected function ApplyDataFilters(): DBObjectSearch
protected function ApplyDataFilters(): DBSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last but not least it could be nice to refactor in one common method. where we would pass an array of string (coming from either GetSearches, GetSelectedClasses or GetJoinedClasses).

		// Apply filter (this is similar to the one in DBSearch but the factorization could make it less readable)
		foreach ($aClassesToFilter as $sClassAlias => $sClass) {
			$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
			if ($oVisibleObjects === false) {
				$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
			}
			if (is_object($oVisibleObjects)) {
				$oVisibleObjects->AllowAllData();
				$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
				$oSearch->SetDataFiltered();
			}
		}

protected function ApplyDataFilters(): DBObjectSearch
protected function ApplyDataFilters(): DBSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to compute GetSelectedClass if 'security.disable_joined_classes_filter' is disabled.

* @return DBUnionSearch
*/
protected function ApplyDataFilters(): DBUnionSearch
protected function ApplyDataFilters(): DBSearch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a pity that we compute further times IsDataAllowed and IsDataFiltered when dealing with Union....

first time in DBUnion. and 2nd time in the loop when calling each sub item.

@Molkobain

Copy link
Copy Markdown
Member Author

@greptileai review again please.

@Molkobain

Copy link
Copy Markdown
Member Author

we should discuss... my guess is that we will focus on the minimum. which is not 100% sure from what i see in the code. i understand that i dont understand everything....

Thanks for the review. We can discuss IRL tomorrow for sure.
Keep in mind that this PR addresses a blocking issue on iTop 3.2.3-2 and is for the 3.2.3-2 micro version, we just want to fix the bug, not rework the feature. But let's dig into this IRL :)

@Molkobain

Copy link
Copy Markdown
Member Author

@greptileai review again please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants