Skip to content

[3.0] Stop the current board being rebuilt into an empty object - #9433

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/board-init-current
Open

[3.0] Stop the current board being rebuilt into an empty object#9433
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/board-init-current

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

Noticed while testing #9432. Any page that has a current board and then walks the
board tree is a 500:

?action=search;board=1.0
?action=search;topic=1
?action=admin;area=manageboards;board=1.0

Typed property SMF\Board::$id must not be accessed before initialization

Category::getTree() rebuilds each board from the row it has just read, and to
do that it drops the old object first:

unset(Board::$loaded[(int) $row['id_board']]);
Board::init((int) $row['id_board'], $row);

For every board but one that is fine. For the board the member is actually on,
Board::init() finds nothing loaded and constructs a new object — and the
constructor sees an id equal to Board::$board_id, takes its "load the current
board"
path, finds Board::$info already set, and returns having assigned
nothing at all
:

if (!isset($id) || (!empty($id) && $id === self::$board_id)) {
    // Only do this once.
    if (!isset(self::$info)) {
        …                       // ← everything, including $this->id, is in here
    }
} else {
    …
    $this->id = $id;
    $this->set($props);
    self::$loaded[$this->id] = $this;
}

// Add this board as a child of its parent.
if (!empty($this->parent)) {          // ← reached either way

What comes back is an object with no id, no name and no anything, and the tail of
the constructor reads $this->id immediately.

The fix

The board is not really gone — Board::$info is still holding it. So put that one
back rather than building a second object claiming to be the same board, and let
the existing branch below apply the fresh row to it. getTree() then finds
Board::$loaded[$id] where it expects it, and the tree it builds refers to the
same instance as the rest of the request rather than to a copy.

The new branch only fires when Board::$info is set, the id is the current board,
and that board is missing from the loaded list — the exact combination that
used to throw. Every other path through init() is untouched.

Testing

Swept 22 pages as an admin, with the current board set to a top level board and
then to a child board (so the parent/child branch of the constructor is
exercised too):

Issues References (Fixes|Related|Closes)

Related to #7933

Any page that has a board and then walks the board tree is a 500:

	?action=search;board=1.0
	?action=search;topic=1
	?action=admin;area=manageboards;board=1.0

	Typed property SMF\Board::$id must not be accessed before initialization

Category::getTree() rebuilds each board from the row it has just read, and to do
that it drops the old object first:

	unset(Board::$loaded[(int) $row['id_board']]);
	Board::init((int) $row['id_board'], $row);

For every board but one that works. For the board the member is actually on,
Board::init() finds nothing loaded and constructs a new object - and the
constructor sees an id equal to Board::$board_id, takes its "load the current
board" path, finds Board::$info already set, and returns having assigned
nothing. What comes back is an object with no id, no name and no anything, and
the tail of the constructor reads $this->id straight away.

The board is not really gone, though: Board::$info is still holding it. So put
that one back instead of building a second object claiming to be the same board,
and let the existing branch below apply the fresh row to it. getTree() then
finds Board::$loaded[$id] where it expects it, and the tree it builds refers to
the same instance as the rest of the request rather than a copy.

Nothing else changes: the new branch only fires when Board::$info is set, the id
is the current board, and that board is missing from the loaded list, which is
the combination that used to throw.

Verified by sweeping 22 pages as an admin, with the current board set to a top
level board and to a child board in turn: the three URLs above now load, every
page that already worked still does, and the board trees on Manage Boards, the
search picker and Manage Permissions come out byte for byte the same as on
release-3.0. The error log is clean apart from the known calendar TimeInterval
fault.

Signed-off-by: Mathias Albert <mathiaspapealbert@hotmail.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@jdarwood007 jdarwood007 added this to the 3.0 Alpha 5 milestone Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants