Journal Entries

Journal Entry, January 31st to February 7th 2020

February 7, 2020 · 2 min read

Laravel

  1. Mon Feb 3

    • Mocking multiple overloads based on arguments.

      $this->mock('overload:Stripe\Charge', function ($mock) {
          $mock->shouldReceive('create')
              ->with(\Mockery::on(function ($argument) {
                  return is_array($argument) && isset($argument['source']) && $argument['source'] == 'card_expired';
              }))
              ->times(1)
              ->andThrow(new \Stripe\Error\InvalidRequest("Source should be a valid card id", null)) // This relies on the try/catch logic in the Job
              ->getMock()
              ->shouldReceive('create')
              ->times(1)
              ->andReturn($this->getTestStripeResponse()); // Overload our instance with this default
      });
    • We ignore our raised exception by you guessed it, a try/catch block.

      try {
          $this->withoutExceptionHandling()->artisan("subscriptions:process-remaining --day={$day} --no-progress")
          ->expectsOutput('4 subscription(s) found');
      } catch(\Throwable $exception) {
      }
      
      \Event::assertDispatched(\App\Events\CardCharged::class, 3);
      
      try {
          $this->withoutExceptionHandling()->artisan("subscriptions:process-remaining --day={$day} --no-progress")
          ->expectsOutput('1 subscription(s) found');
      } catch(\Throwable $exception) {
      }
  2. Wed Feb 2

    • Laravel Queue generic exception Illuminate\Queue\MaxAttemptsExceededException
    • This stack trace shows the method call set at 5 maxTries:

      Illuminate\Queue\MaxAttemptsExceededException: App\Jobs\PendingOrderTransferJob has been attempted too many times or run too long. The job may have previously timed out. in /home/forge/obr.rethinkgroup.org/vendor/laravel/framework/src/Illuminate/Queue/Worker.php:394
      Stack trace:
      #0 /home/forge/obr.rethinkgroup.org/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(314): Illuminate\Queue\Worker->markJobAsFailedIfAlreadyExceedsMaxAttempts('redis:horizon', Object(Illuminate\Queue\Jobs\RedisJob), 5)
    • The failed job payload shows 5 attempts were made:

      {"type":"job","timeout":null,"tags":["App\\Model\\PendingOrderStatus:1534"],"id":"3078","data":{"command":"O:32:\"App\\Jobs\\PendingOrderTransferJob\":8:{s:6:\"status\";O:45:\"Illuminate\\Contracts\\Database\\ModelIdentifier\":3:{s:5:\"class\";s:28:\"App\\Model\\PendingOrderStatus\";s:2:\"id\";i:1534;s:10:\"connection\";s:5:\"mysql\";}s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";s:13:\"redis:horizon\";s:5:\"queue\";s:15:\"orders:transfer\";s:15:\"chainConnection\";N;s:10:\"chainQueue\";N;s:5:\"delay\";N;s:7:\"chained\";a:0:{}}","commandName":"App\\Jobs\\PendingOrderTransferJob"},"displayName":"App\\Jobs\\PendingOrderTransferJob","timeoutAt":null,"pushedAt":"1580851619.0033","maxTries":null,"job":"Illuminate\\Queue\\CallQueuedHandler@call","attempts":5}

Journal Entry, December 13th to December 20th 2019

December 20, 2019 · 1 min read

Laravel

  1. Mon Dec 16

    • Reminder of JSON fields

      $table->json('source_payload');
      $table->string('order_id')->storedAs('source_payload->>"$.eCommerceOrderId"');
      $table->string('user_id')->storedAs('source_payload->>"$.eCommerceCustomerId"');
      $table->string('organization_id')->storedAs('source_payload->>"$.obrorgid"');
      
      // See https://themsaid.com/laravel-mysql-json-colum-fast-lookup-20160709/
      $table->index('order_id');
      $table->index('user_id');
      $table->index('organization_id');
      SELECT
          *, payload->>"$[0].eCommerceCustomerId" as `eCommerceCustomerId`
      FROM
          pendingOrderStatus
      WHERE
          payload->>"$[0].eCommerceCustomerId" = '16350';

Journal Entry, November 15th to November 22nd 2019

November 22, 2019 · 1 min read

Laravel Nova

  1. Mon Nov 18

    • The following is necessary as name isn't a publicly accessible property facepalm.
    • Using name is allowed oddly enough but sorting isn't respected so my guess is Laravel can't find the property and tries to sort by the object instead.
    • It's extremely off-putting to see it partially sort and have no fucking clue why it didn't fully sort as expected. I spent longer than I should've and hated myself when I found the answer.

      return $categories->sortBy(function(\App\Classes\Uploads\Category $category) {
          return $category->getName();
      }, SORT_NATURAL);

Journal Entry, October 11th to October 18th 2019

October 18, 2019 · 1 min read

Laravel Nova

  1. Wed Oct 16

    • The can method is on the user as authorization always attaches to the current logged in user
    • The following specifies checking the sendReceipt() method in the OrderPolicy

      (new Actions\SendReceipt)->canSee(function ($request) {
          return $request->user()->can('sendReceipt', \App\Models\Order::class);
      })->canRun(function ($request, $order) {
          return $request->user()->can('sendReceipt', \App\Models\Order::class);
      }),

Journal Entry, October 4th to October 11th 2019

October 11, 2019 · 2 min read

Elixir

  1. Thu Oct 10

    • Compiling elixir language EPUB
    • How to generate EPUB documentation for Elixir v1.6

      • Note: You must remove your phx_new mix archive (mix archive.uninstall phx_new-1.4.10) or conflicts happen during the build process
      git clone https://github.com/phoenixframework/phoenix.git
      cd phoenix
      git checkout v1.4 (or next completed)
      mix deps.get
      mix docs --formatter epub
      git clone https://github.com/elixir-lang/elixir-lang.github.com.git
      git clone https://github.com/elixir-lang/elixir.git
      cd elixir
      
      nano Makefile
      #==> Documentation tasks
      # DOCS_FORMAT = html
      DOCS_FORMAT = epub
      
      make docs
      
      cp doc/elixir/Elixir.epub

Elixir Koans

  1. Tue Oct 8

    • IEx testing a file

      • import_file("lib/knockin/tasks/stack_overflow_query.ex")
      • data = %Knockin.Tasks.StackOverflowQuery{}
      • Knockin.Tasks.StackOverflowQuery.get_base_url
    • Sort order

      • number < atom < reference < function < port < pid < tuple < map < list < bitstring
    • Collections

      • Lists - Simple collection of values
      • Tuples - Lists stored contiguously. Expensive as modifications require copying the entire tuple
      • Keyword lists - a special list of two-element tuples whose first element is an atom; they share performance with lists
      • Maps - the “go-to” key-value store. Unlike keyword lists, they allow keys of any type and are un-ordered.
    • Enum - Set of algorithms for enumerating over enumerables

      • all? - Returns true if supplied callback applies to all values
      • any? - Returns true if supplied callback applies to a single value
      • chunk_every
      • chunk_by
      • map_every
      • each
      • map
      • min
      • max
      • filter
      • reduce
      • sort
      • uniq
      • uniq_by
    • Pattern matching - allows us to match simple values, data structures, and even functions

      • Match operator (=) - Turns into an equation, the left side has to match the right
      • Pin operator (^) - With the match operator, variable assignment happens if included on the left. The pin operator prevents rebinding
      • Any equation or assignment seems to set a pattern or match
    • Control structures

      • if and unless - if looks for truthy, unless is the inverse and defaults to false
      • case - match against multiple patterns. _ required in the event there is no match (like default in other languages but required, unlike others). Allows for guard clauses
      • cond - Match conditions instead of values, akin to else if from other languages
      • with - (Need to look this up)

Laravel Nova

  1. Tue Oct 8

    • You need to run nova:publish as Nova updates via composer. It's easier, if using composer, to run the commands on update.
    • https://twitter.com/freekmurze/status/1169233283269451776 is what happens when this generally breaks but the docs don't point this out in a painfully obvious way.
    • Make a blog post on Chrome overrides and looking at Nova in Vue devtools.

Journal Entry, September 27th to October 4th 2019

October 4, 2019 · 3 min read

Elixir Koans

  1. Wed Oct 2

    • Used asdf over docker image
    • Docker had issues installing the filesystem dependency?
    • Looks like docker works after asdf. My guess is it needed the deps directory as if docker isn't sharing the directory normally.
    • Structs

      • Is %Person{} right for the first answer? I looked at the code, not the text to answer it.
    • Sigils
    • Pattern Matching

      • Very difficult to reason about this example
      assert_raise MatchError, fn ->
          [a, b] = [1, 2, 3]
      end
      koan "The pattern can make assertions about what it expects" do
          assert match?([1, _second, _third], [1, 2, 3])
      end
      • It helps to remember that it's looking for the pattern that gets pulled out, not a left = right scenario
      • I clearly don't understand this part and it's one of the more powerful aspects of the language. I don't even know where to begin to get a deeper understanding of how to use it.
    • Functions

      • Understand the default in this case was 5
      koan "Functions can have default argument values" do
          assert repeat_again("Hello ") == "Hello Hello Hello Hello Hello "
          assert repeat_again("Hello ", 2) == "Hello Hello "
      end
      • Understand the function was building output, look for things like [] or {}
      koan "You can build anonymous functions out of any elixir expression by prefixing it with &" do
          three_times = &[&1, &1, &1]
          assert three_times.("foo") == ["foo", "foo", "foo"]
      end
      • Understand the flow of FP, take the first result 10 then pipe it to the second result, square 100. Then divide by 1
      koan "You can pass functions around as arguments. Place an '&' before the name and state the arity" do
          assert times_five_and_then(2, &square/1) == 100
      end
    • Enums

      • Seems that anything with ? becomes a boolean check or it's just how it's used in all of these examples based on how they define functions
      koan "Elements can have a lot in common" do
          assert Enum.all?([1, 2, 3], &less_than_five?/1) == true
          assert Enum.all?([4, 6, 8], &less_than_five?/1) == false
      end
      • Take the first 3, not take the literal instance of 3
      koan "You three there, follow me!" do
          assert Enum.take([1, 2, 3, 4, 5], 3) == [1, 2, 3]
      end
      • I have a feeling this syntax is important
      koan "Zip-up in pairs!" do
          letters = [:a, :b, :c]
          numbers = [1, 2, 3]
          assert Enum.zip(letters, numbers) == [a: 1, b: 2, c: 3]
      end
      • Unsure why 4 doesn't work here. Does it return the first element?
      koan "When you want to find that one pesky element" do
          assert Enum.find([1, 2, 3, 4], &even?/1) == 2
      end
  2. Thu Oct 3

    • Processes

      koan "You can ask a process to introduce itself" do
          information = Process.info(self())
      
          assert information[:status] == :running
      end
      • It's hard to really understand where this would be useful except to spawn processes or to cleanup/log on exit
    • Tasks
    • Agents

      • It's also hard to understand the use cases for pretty much all the above, processes, tasks, and agents. There seems to be a bit of overlap between them.
    • GenServers

      • This is perhaps one of the more extensive and fun as the response is in the declaration (like most of these) but it's more about hunting and finding the response you expect.
      • One of the best examples of pattern matching, or anything shows as less emphasis in VSCode's syntax highlighting
      koan "Let's use the remaining functions in the external API" do
          Laptop.start_link("EL!73")
          {_, response} = Laptop.unlock("EL!73")
          assert response == "Laptop unlocked!"
      
          Laptop.change_password("EL!73", "Elixir")
          {_, response} = Laptop.unlock("EL!73")
          assert response == "Incorrect password!"
      
          {_, response} = Laptop.owner_name()
          assert response == "Jack Sparrow"
      end
    • Protocols

      • Seem like implementation details and helpful for defining contracts and concrete definitions. It's a little unclear what the preference for using this is.
    • Comprehensions

      • A little harder to understand this is multiple lists not coercing to one long string. I tried "Hello World Apple Pie" at first.
      koan "A generator specifies how to extract values from a collection" do
          collection = [["Hello","World"], ["Apple", "Pie"]]
          assert (for [a, b] <- collection, do: "#{a} #{b}") == ["Hello World", "Apple Pie"]
      end
      • Turns out this one is unlike the one before it where my initial instincts were closer to correct.
      koan "You can use multiple generators at once" do
          assert (for x <- ["little", "big"], y <- ["dogs", "cats"], do: "#{x} #{y}") == ["little dogs", "little cats", "big dogs", "big cats"]
      end

Journal Entry, September 20th to September 27th 2019

September 27, 2019 · 1 min read

Laravel Nova

  1. Fri Sep 27

    • Customize download file name using record information.

      /**
       * Get the actions available for the resource.
       *
       * @param  \Illuminate\Http\Request  $request
       * @return array
       */
      public function actions(Request $request)
      {
          $fileName = $this->getDownloadFileName($request);
          return [
              (new DownloadExcel)->withFilename($fileName)
                                  ->withWriterType(\Maatwebsite\Excel\Excel::CSV)
                                  ->withName('Download CSV')
                                  ->withHeadings()
                                  ->only('code')
                                  ->onlyOnIndex()
                                  ->withoutConfirmation(),
          ];
      }
      
      /**
       * Get the filename for the DownloadExcel action.
       *
       * @param  \Illuminate\Http\Request  $request
       * @return string
       */
      private function getDownloadFileName(Request $request)
      {
          $result = 'codes-' . time() . '.csv';
          try {
              $batch = $request->findModelQuery()->getParent();
              $result = \Str::slug($batch->codeType->name) . "-{$batch->id}-codes.csv";
          } catch (\Exception $exception) {
          }
          return $result;
      }

Journal Entry, August 9th to August 16th 2019

August 16, 2019 · 1 min read

Vue

  1. Mon Aug 12 2019

    • In a Vue component with a data prop titled selectedBucket, if you emit an event named selectedBucketChanged you'll see the event emitted twice. I believe it's because there are life cycle events for any prop that are emitted for reactivity that I just happened to trample on.
    • It would be useful to determine if this is in fact true or an incorrect guess.

Journal Entry, July 26th to August 2nd 2019

August 2, 2019 · 1 min read

Laravel

  1. Tue Jul 30

    • Laravel streaming upload from one filesystem (local/legacy) to another (spaces).

      $resource = \Storage::disk('legacy')->readStream($source);
      $status = \Storage::disk($this->disk)->put($destination, $resource, 'public');
      $sourceSize = \Storage::disk('legacy')->size($source);
      $destinationSize = \Storage::disk($this->disk)->size($destination);
  2. Wed Jul 31

    • It seems the disk cloud doesn't really coerce down to spaces or s3.
    • Required running the command using the disk reference itself: ./artisan convert:material-assets -d spaces --no-progress --reset

Vue

  1. Thu Aug 1

    • Chrome overrides to enable Vue devtools.

      • Open Chrome DevTools (cmd-opt-I)
      • Click Sources tab.
      • Click >> and select Overrides.
      • Click + Select folder for overrides.
      • Navigate to a directory to store your page overrides.
      • Chrome prompts with something like "DevTools requests full access to (directory)..." , click Allow.
      • Now that your overrides folder is setup, click Page under the sources tab to show the files for the page.
      • Navigate to the file you wish to save.
      • Right click and select Save for overrides. This places the file in a site/folder location.
      • Click the {} to pretty print the javascript.
      • Type Ctrl-F to show the find box.
      • Type in devtools and hit enter.
      • You should see an object named H or something unique to each compiled instance. This object could be named absolutely anything.
      • You should see an entry marked something like:
         productionTip: !1, 
         devtools: !1,
         performance: !1,
      • Change the devtools line from !1 to 1 for true.
      • Type Ctrl-S to save the changes.
      • Reload the page and look for the Vue tab. It may take a few reloads for everything to initialize properly.
      • Inspect your production Vue instance like a boss.

Journal Entry, July 12th to July 19th 2019

July 19, 2019 · 1 min read

MySQL

  1. Mon Jul 15 2019

    • Json field queries

      SELECT
          *, `payload`->"$[0].eCommerceOrderId" AS `e_commerce_order_id`
      FROM
          pendingOrderStatus
      WHERE
          `status` = 'sent';
      SELECT
          id, `order`->>'$.e_commerce_order_id' AS `e_commerce_order_id`
      FROM
          order_log_transforms
      WHERE
          `order`->>'$.e_commerce_order_id' IS NOT NULL;
  2. Wed Jul 17 2019

    • Importing from the source table in one database to the destination in another database.

      INSERT INTO `materials-staging`.`files` (`id`, `path`, `type`, `hash`, `material_id`, `active`, `created_at`, `updated_at`, `deleted_at`)
      SELECT
          *
      FROM
          `materials_staging`.`mat_files`;