Refactor SystemPCIeFunctionCollection method

Move SystemPCIeFunctionCollection to a separate method, and refactor
the code.

Validate the PCIe device path and add link header.

Tested: Validator passed

```
{
  "@odata.id": "/redfish/v1/Systems/system/PCIeDevices/pcie_card7/PCIeFunctions",
  "@odata.type": "#PCIeFunctionCollection.PCIeFunctionCollection",
  "Description": "Collection of PCIe Functions for PCIe Device pcie_card7",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Systems/system/PCIeDevices/pcie_card7/PCIeFunctions/0"
    }
  ],
  "Name": "PCIe Function Collection",
  "PCIeFunctions@odata.count": 1
}
```

Change-Id: I5aa10ce0b4d2f20104612f840cf4098698a83470
Signed-off-by: Lakshmi Yadlapati <lakshmiy@us.ibm.com>
diff --git a/redfish-core/lib/pcie.hpp b/redfish-core/lib/pcie.hpp
index 969e1fa..4bf5626 100644
--- a/redfish-core/lib/pcie.hpp
+++ b/redfish-core/lib/pcie.hpp
@@ -224,7 +224,7 @@
 }
 
 inline void addPCIeDeviceProperties(
-    crow::Response& resp,
+    crow::Response& resp, const std::string& pcieDeviceId,
     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
 {
     const std::string* manufacturer = nullptr;
@@ -276,6 +276,10 @@
     {
         resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer;
     }
+
+    resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces(
+        "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
+        "PCIeFunctions");
 }
 
 inline void getPCIeDeviceProperties(
@@ -339,8 +343,10 @@
         addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
         getPCIeDeviceProperties(
             aResp, pcieDevicePath, service,
-            [aResp](const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
-            addPCIeDeviceProperties(aResp->res, pcieDevProperties);
+            [aResp, pcieDeviceId](
+                const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
+            addPCIeDeviceProperties(aResp->res, pcieDeviceId,
+                                    pcieDevProperties);
             });
         });
 }
@@ -353,6 +359,77 @@
             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
 }
 
+inline void addPCIeFunctionList(
+    crow::Response& res, const std::string& pcieDeviceId,
+    const dbus::utility::DBusPropertiesMap& pcieDevProperties)
+{
+    nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
+    pcieFunctionList = nlohmann::json::array();
+    static constexpr const int maxPciFunctionNum = 8;
+
+    for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
+    {
+        // Check if this function exists by
+        // looking for a device ID
+        std::string devIDProperty =
+            "Function" + std::to_string(functionNum) + "DeviceId";
+        const std::string* property = nullptr;
+        for (const auto& propEntry : pcieDevProperties)
+        {
+            if (propEntry.first == devIDProperty)
+            {
+                property = std::get_if<std::string>(&propEntry.second);
+                break;
+            }
+        }
+        if (property == nullptr || property->empty())
+        {
+            continue;
+        }
+
+        nlohmann::json::object_t pcieFunction;
+        pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
+            "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
+            "PCIeFunctions", std::to_string(functionNum));
+        pcieFunctionList.push_back(std::move(pcieFunction));
+    }
+    res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
+}
+
+inline void handlePCIeFunctionCollectionGet(
+    App& app, const crow::Request& req,
+    const std::shared_ptr<bmcweb::AsyncResp>& aResp,
+    const std::string& pcieDeviceId)
+{
+    if (!redfish::setUpRedfishRoute(app, req, aResp))
+    {
+        return;
+    }
+
+    getValidPCIeDevicePath(
+        pcieDeviceId, aResp,
+        [aResp, pcieDeviceId](const std::string& pcieDevicePath,
+                              const std::string& service) {
+        aResp->res.addHeader(
+            boost::beast::http::field::link,
+            "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
+        aResp->res.jsonValue["@odata.type"] =
+            "#PCIeFunctionCollection.PCIeFunctionCollection";
+        aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
+            "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
+            "PCIeFunctions");
+        aResp->res.jsonValue["Name"] = "PCIe Function Collection";
+        aResp->res.jsonValue["Description"] =
+            "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
+        getPCIeDeviceProperties(
+            aResp, pcieDevicePath, service,
+            [aResp, pcieDeviceId](
+                const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
+            addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
+            });
+        });
+}
+
 inline void requestRoutesSystemPCIeFunctionCollection(App& app)
 {
     /**
@@ -362,83 +439,7 @@
                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
         .privileges(redfish::privileges::getPCIeFunctionCollection)
         .methods(boost::beast::http::verb::get)(
-            [&app](const crow::Request& req,
-                   const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
-                   const std::string& device) {
-        if (!redfish::setUpRedfishRoute(app, req, asyncResp))
-        {
-            return;
-        }
-
-        asyncResp->res.jsonValue["@odata.type"] =
-            "#PCIeFunctionCollection.PCIeFunctionCollection";
-        asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
-            "redfish", "v1", "Systems", "system", "PCIeDevices", device,
-            "PCIeFunctions");
-        asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
-        asyncResp->res.jsonValue["Description"] =
-            "Collection of PCIe Functions for PCIe Device " + device;
-
-        auto getPCIeDeviceCallback =
-            [asyncResp, device](
-                const boost::system::error_code& ec,
-                const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
-            if (ec)
-            {
-                BMCWEB_LOG_DEBUG
-                    << "failed to get PCIe Device properties ec: " << ec.value()
-                    << ": " << ec.message();
-                if (ec.value() ==
-                    boost::system::linux_error::bad_request_descriptor)
-                {
-                    messages::resourceNotFound(asyncResp->res, "PCIeDevice",
-                                               device);
-                }
-                else
-                {
-                    messages::internalError(asyncResp->res);
-                }
-                return;
-            }
-
-            nlohmann::json& pcieFunctionList =
-                asyncResp->res.jsonValue["Members"];
-            pcieFunctionList = nlohmann::json::array();
-            static constexpr const int maxPciFunctionNum = 8;
-            for (int functionNum = 0; functionNum < maxPciFunctionNum;
-                 functionNum++)
-            {
-                // Check if this function exists by looking for a
-                // device ID
-                std::string devIDProperty =
-                    "Function" + std::to_string(functionNum) + "DeviceId";
-                const std::string* property = nullptr;
-                for (const auto& propEntry : pcieDevProperties)
-                {
-                    if (propEntry.first == devIDProperty)
-                    {
-                        property = std::get_if<std::string>(&propEntry.second);
-                    }
-                }
-                if (property == nullptr || property->empty())
-                {
-                    continue;
-                }
-                nlohmann::json::object_t pcieFunction;
-                pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
-                    "redfish", "v1", "Systems", "system", "PCIeDevices", device,
-                    "PCIeFunctions", std::to_string(functionNum));
-                pcieFunctionList.push_back(std::move(pcieFunction));
-            }
-            asyncResp->res.jsonValue["Members@odata.count"] =
-                pcieFunctionList.size();
-        };
-        std::string escapedPath = std::string(pciePath) + "/" + device;
-        dbus::utility::escapePathForDbus(escapedPath);
-        sdbusplus::asio::getAllProperties(
-            *crow::connections::systemBus, pcieService, escapedPath,
-            pcieDeviceInterface, std::move(getPCIeDeviceCallback));
-        });
+            std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
 }
 
 inline void requestRoutesSystemPCIeFunction(App& app)