Journal Entry, November 6th to November 13th 2020

November 13, 2020 · 2 min read

Laravel

  1. Mon Nov 9

    • To introduce a blocklist to filter out apiLog records, we first filter by application_id and then 1 or more arrays of values.
    • This lets us do thing like filter multiple statuses, methods, or uris.
    • Ideally we could take it a step further and filter by only status 422 or DELETE methods but the 1 or more aspect makes things seemingly more difficult.
    • Initially my brain halted using nested conditionals in a "if value is present then check the other fields" repeated.
    • The null coalescing operator is doing this for us by either returning null when nothing is found or the result of the in_array check if present.
    • Because something like null ?? false ?? true returns true, it feels almost hackish but I suspect works for any field we throw at it.
    • My first attempt was to have an array of application_id but this made the Collection->where() usage more difficult.

      {
          "blocklist": [
              {
                  "application_id": ["SAGESYNC", "SAGESYNCMS"],
                  "status": ["422"]
              },
              {
                  "application_id": ["SAGESYNCXC4"]
              }
          ]
      }
    • Ultimately we had to settle on this form as the where() clause looks for values.

      {
          "blocklist": [
              {
                  "application_id": "SAGESYNC",
                  "status": ["422"]
              },
              {
                  "application_id": "SAGESYNCMS",
                  "status": ["422"]
              },
              {
                  "application_id": "SAGESYNCXC4"
              }
          ]
      }
      /**
       * Filter columns against configured blocklist.
       *
       * @param string|null $application_id
       * @param string|null $method
       * @param string|null $uri
       * @param string|null $status
       * @return void
       */
      public function isBlocked($application_id, $method, $uri, $status)
      {
          $result = false;
          $blocklist = collect($this->getBlocklist());
          $blocked = $blocklist->where('application_id', $application_id);
          $blocked->each(function ($block) use (&$result, $method, $uri, $status) {
              $methods = Arr::get($block, 'method', null);
              $uris = Arr::get($block, 'uri', null);
              $statuses = Arr::get($block, 'status', null);
              $filtered = $this->hasValue($methods, $method) ?? $this->hasValue($uris, $uri) ?? $this->hasValue($statuses, $status);
              if (is_null($filtered) || $filtered === true) {
                  // $filtered is true when a value is found or null when all fields are null.
                  $result = true;
              }
          });
      
          return $result;
      }
      
      /**
       * An array has value (has normally checks for keys not values).
       *
       * @param array|null $array
       * @param mixed $value
       * @return boolean
       */
      private function hasValue($array, $value)
      {
          if (is_null($array)) {
              return null;
          }
      
          return in_array($value, $array);
      }
      
      /**
       * Retrieve blocklist section from config file.
       *
       * @return null|array
       */
      private function getBlocklist()
      {
          $localDisk = \Storage::disk('local');
          $contents = $localDisk->get("data/apiLogs/config.json");
          $json = json_decode($contents, true);
      
          if (!is_null($json)) {
              return $json['blocklist'];
          }
      
          return null;
      }