From ee1c399193ca5d50874770f695466fb1aecf577c Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Fri, 14 Mar 2025 18:31:45 +0000
Subject: [PATCH] Issue #3347502 by spokje, longwave, ankithashetty, quietone,
 smustgrave, mondrake: Fix PHPStan L1 errors "Access to an undefined property
 Foo\Bar::$baz" (Low Hanging Fruit Edition)

---
 core/.phpstan-baseline.php                    | 60 -------------------
 core/lib/Drupal/Core/Entity/EntityBase.php    |  2 +-
 .../Field/FieldType/NumericItemBase.php       |  7 +--
 .../Drupal/Core/FileTransfer/FTPExtension.php |  7 +++
 core/lib/Drupal/Core/FileTransfer/SSH.php     |  7 +++
 .../Plugin/Field/FieldType/DateTimeItem.php   |  2 +-
 .../Plugin/Field/FieldType/DateRangeItem.php  |  4 +-
 .../src/Plugin/Field/FieldType/ImageItem.php  | 10 ++--
 .../Plugin/Field/FieldType/ListItemBase.php   |  4 +-
 .../src/Plugin/Field/FieldType/PathItem.php   | 36 ++++++-----
 10 files changed, 51 insertions(+), 88 deletions(-)

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index 307798731439..5937ccef90f8 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -5011,12 +5011,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\Core\\\\Entity\\\\EntityBase\\:\\:\\$id\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 1,
-	'path' => __DIR__ . '/lib/Drupal/Core/Entity/EntityBase.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\Core\\\\Entity\\\\EntityBase\\:\\:__get\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
@@ -7579,12 +7573,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\Plugin\\\\Field\\\\FieldType\\\\NumericItemBase\\:\\:\\$value\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 1,
-	'path' => __DIR__ . '/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\Core\\\\Field\\\\Plugin\\\\Field\\\\FieldType\\\\PasswordItem\\:\\:preSave\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
@@ -16725,18 +16713,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeFieldItemList.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\datetime_range\\\\Plugin\\\\Field\\\\FieldType\\\\DateRangeItem\\:\\:\\$end_date\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\datetime_range\\\\Plugin\\\\Field\\\\FieldType\\\\DateRangeItem\\:\\:\\$start_date\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\datetime_range\\\\Plugin\\\\Field\\\\FieldType\\\\DateRangeItem\\:\\:onChange\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
@@ -20175,18 +20151,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/image/src/ImageStyleStorageInterface.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\image\\\\Plugin\\\\Field\\\\FieldType\\\\ImageItem\\:\\:\\$height\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 2,
-	'path' => __DIR__ . '/modules/image/src/Plugin/Field/FieldType/ImageItem.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\image\\\\Plugin\\\\Field\\\\FieldType\\\\ImageItem\\:\\:\\$width\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 2,
-	'path' => __DIR__ . '/modules/image/src/Plugin/Field/FieldType/ImageItem.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\image\\\\Plugin\\\\Field\\\\FieldType\\\\ImageItem\\:\\:defaultImageForm\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
@@ -29289,12 +29253,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/options/options.module',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\options\\\\Plugin\\\\Field\\\\FieldType\\\\ListItemBase\\:\\:\\$value\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/options/src/Plugin/Field/FieldType/ListItemBase.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\options\\\\Plugin\\\\Field\\\\FieldType\\\\ListItemBase\\:\\:addMoreAjax\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
@@ -29529,24 +29487,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/path/src/Plugin/Field/FieldType/PathFieldItemList.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\path\\\\Plugin\\\\Field\\\\FieldType\\\\PathItem\\:\\:\\$alias\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 3,
-	'path' => __DIR__ . '/modules/path/src/Plugin/Field/FieldType/PathItem.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\path\\\\Plugin\\\\Field\\\\FieldType\\\\PathItem\\:\\:\\$langcode\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 2,
-	'path' => __DIR__ . '/modules/path/src/Plugin/Field/FieldType/PathItem.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Access to an undefined property Drupal\\\\path\\\\Plugin\\\\Field\\\\FieldType\\\\PathItem\\:\\:\\$pid\\.$#',
-	'identifier' => 'property.notFound',
-	'count' => 5,
-	'path' => __DIR__ . '/modules/path/src/Plugin/Field/FieldType/PathItem.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\path\\\\Plugin\\\\Field\\\\FieldType\\\\PathItem\\:\\:postSave\\(\\) should return bool but return statement is missing\\.$#',
 	'identifier' => 'return.missing',
diff --git a/core/lib/Drupal/Core/Entity/EntityBase.php b/core/lib/Drupal/Core/Entity/EntityBase.php
index ad048198d1fb..aa25d63c0067 100644
--- a/core/lib/Drupal/Core/Entity/EntityBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityBase.php
@@ -417,7 +417,7 @@ public function preSave(EntityStorageInterface $storage) {
     if ($this->getEntityType()->getBundleOf()) {
       // Throw an exception if the bundle ID is longer than 32 characters.
       if (mb_strlen($this->id()) > EntityTypeInterface::BUNDLE_MAX_LENGTH) {
-        throw new ConfigEntityIdLengthException("Attempt to create a bundle with an ID longer than " . EntityTypeInterface::BUNDLE_MAX_LENGTH . " characters: $this->id().");
+        throw new ConfigEntityIdLengthException("Attempt to create a bundle with an ID longer than " . EntityTypeInterface::BUNDLE_MAX_LENGTH . " characters: " . $this->id() . ".");
       }
     }
   }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
index 1e4fbbb2b6da..fb1bea28c5cd 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
@@ -64,10 +64,9 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function isEmpty() {
-    if (empty($this->value) && (string) $this->value !== '0') {
-      return TRUE;
-    }
-    return FALSE;
+    $value = $this->get('value')->getValue();
+
+    return empty($value) && (string) $value !== '0';
   }
 
   /**
diff --git a/core/lib/Drupal/Core/FileTransfer/FTPExtension.php b/core/lib/Drupal/Core/FileTransfer/FTPExtension.php
index d47948226360..8c22591984be 100644
--- a/core/lib/Drupal/Core/FileTransfer/FTPExtension.php
+++ b/core/lib/Drupal/Core/FileTransfer/FTPExtension.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\FileTransfer;
 
+use FTP\Connection;
+
 /**
  * Defines a file transfer class using the PHP FTP extension.
  *
@@ -12,6 +14,11 @@
  */
 class FTPExtension extends FTP implements ChmodInterface {
 
+  /**
+   * The FTP connection.
+   */
+  protected Connection|false $connection;
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/FileTransfer/SSH.php b/core/lib/Drupal/Core/FileTransfer/SSH.php
index 5524ef6efafb..6b7d983eef59 100644
--- a/core/lib/Drupal/Core/FileTransfer/SSH.php
+++ b/core/lib/Drupal/Core/FileTransfer/SSH.php
@@ -12,6 +12,13 @@
  */
 class SSH extends FileTransfer implements ChmodInterface {
 
+  /**
+   * The connection.
+   *
+   * @var resource|false
+   */
+  protected $connection;
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
index 68742eba0583..ee180cfd1c6e 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
@@ -137,7 +137,7 @@ public function isEmpty() {
   public function onChange($property_name, $notify = TRUE) {
     // Enforce that the computed date is recalculated.
     if ($property_name == 'value') {
-      $this->date = NULL;
+      $this->set('date', NULL);
     }
     parent::onChange($property_name, $notify);
   }
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php b/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php
index 85680e691463..f3999f349b49 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldType/DateRangeItem.php
@@ -128,10 +128,10 @@ public function isEmpty() {
   public function onChange($property_name, $notify = TRUE) {
     // Enforce that the computed date is recalculated.
     if ($property_name == 'value') {
-      $this->start_date = NULL;
+      $this->set('start_date', NULL);
     }
     elseif ($property_name == 'end_value') {
-      $this->end_date = NULL;
+      $this->set('end_date', NULL);
     }
     parent::onChange($property_name, $notify);
   }
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index 2cae36dc6cf6..50e7111a4795 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -326,16 +326,16 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
   public function preSave() {
     parent::preSave();
 
-    $width = $this->width;
-    $height = $this->height;
+    $width = $this->get('width')->getValue();
+    $height = $this->get('height')->getValue();
 
     // Determine the dimensions if necessary.
     if ($this->entity && $this->entity instanceof EntityInterface) {
-      if (empty($width) || empty($height)) {
+      if ($width === NULL || $height === NULL) {
         $image = \Drupal::service('image.factory')->get($this->entity->getFileUri());
         if ($image->isValid()) {
-          $this->width = $image->getWidth();
-          $this->height = $image->getHeight();
+          $this->set('width', $image->getWidth());
+          $this->set('height', $image->getHeight());
         }
       }
     }
diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
index 8a5d317dc4d4..2a87d03fa9a8 100644
--- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
+++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php
@@ -83,7 +83,9 @@ public static function generateSampleValue(FieldDefinitionInterface $field_defin
    * {@inheritdoc}
    */
   public function isEmpty() {
-    return empty($this->value) && (string) $this->value !== '0';
+    $value = $this->get('value')->getValue();
+
+    return empty($value) && (string) $value !== '0';
   }
 
   /**
diff --git a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
index 6dd9111b225d..ed7adef588fd 100644
--- a/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
+++ b/core/modules/path/src/Plugin/Field/FieldType/PathItem.php
@@ -48,15 +48,20 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
    * {@inheritdoc}
    */
   public function isEmpty() {
-    return ($this->alias === NULL || $this->alias === '') && ($this->pid === NULL || $this->pid === '') && ($this->langcode === NULL || $this->langcode === '');
+    $alias = $this->get('alias')->getValue();
+    $pid = $this->get('pid')->getValue();
+    $langcode = $this->get('langcode')->getValue();
+
+    return ($alias === NULL || $alias === '') && ($pid === NULL || $pid === '') && ($langcode === NULL || $langcode === '');
   }
 
   /**
    * {@inheritdoc}
    */
   public function preSave() {
-    if ($this->alias !== NULL) {
-      $this->alias = trim($this->alias);
+    $alias = $this->get('alias')->getValue();
+    if ($alias !== NULL) {
+      $this->set('alias', trim($alias));
     }
   }
 
@@ -66,35 +71,38 @@ public function preSave() {
   public function postSave($update) {
     $path_alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
     $entity = $this->getEntity();
+    $alias = $this->get('alias')->getValue();
+    $pid = $this->get('pid')->getValue();
+    $langcode = $this->get('langcode')->getValue();
 
     // If specified, rely on the langcode property for the language, so that the
     // existing language of an alias can be kept. That could for example be
     // unspecified even if the field/entity has a specific langcode.
-    $alias_langcode = ($this->langcode && $this->pid) ? $this->langcode : $this->getLangcode();
+    $alias_langcode = ($langcode && $pid) ? $langcode : $this->getLangcode();
 
     // If we have an alias, we need to create or update a path alias entity.
-    if ($this->alias) {
-      if (!$update || !$this->pid) {
+    if ($alias) {
+      if (!$update || !$pid) {
         $path_alias = $path_alias_storage->create([
           'path' => '/' . $entity->toUrl()->getInternalPath(),
-          'alias' => $this->alias,
+          'alias' => $alias,
           'langcode' => $alias_langcode,
         ]);
         $path_alias->save();
-        $this->pid = $path_alias->id();
+        $this->set('pid', $path_alias->id());
       }
-      elseif ($this->pid) {
-        $path_alias = $path_alias_storage->load($this->pid);
+      else {
+        $path_alias = $path_alias_storage->load($pid);
 
-        if ($this->alias != $path_alias->getAlias()) {
-          $path_alias->setAlias($this->alias);
+        if ($alias != $path_alias->getAlias()) {
+          $path_alias->setAlias($alias);
           $path_alias->save();
         }
       }
     }
-    elseif ($this->pid && !$this->alias) {
+    elseif ($pid) {
       // Otherwise, delete the old alias if the user erased it.
-      $path_alias = $path_alias_storage->load($this->pid);
+      $path_alias = $path_alias_storage->load($pid);
       if ($entity->isDefaultRevision()) {
         $path_alias_storage->delete([$path_alias]);
       }
-- 
GitLab