Warning: The magic method SFML_Singleton::__wakeup() must have public visibility in /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php on line 72

Warning: Cannot modify header information - headers already sent by (output started at /home/public/wp-content/plugins/sf-move-login/inc/classes/class-sfml-singleton.php:72) in /home/public/wp-includes/feed-rss2.php on line 8
Uncategorised – Thoughts, etc. https://www.munderwood.ca Tracking the occasional random walk Mon, 27 Mar 2017 16:26:58 +0000 en-CA hourly 1 https://wordpress.org/?v=5.7.2 https://www.munderwood.ca/wp-content/uploads/2016/03/photo-150x150.jpg Uncategorised – Thoughts, etc. https://www.munderwood.ca 32 32 Ember’s live reload server doesn’t live reload addons https://www.munderwood.ca/index.php/2017/03/13/embers-live-reload-server-doesnt-live-reload-addons/ https://www.munderwood.ca/index.php/2017/03/13/embers-live-reload-server-doesnt-live-reload-addons/#respond Mon, 13 Mar 2017 20:46:07 +0000 http://www.munderwood.ca/?p=181 [Read more...]]]> The title pretty much says it all on this one. I just started playing around with Ember, and one of the first things I tried to do was include the ember-simple-auth addon in a brand new project. I tried following the step-by-step instructions in the readme as well as the ones shown in the introductory video. Nothing I did seemed to work; I just kept getting the error  Attempting to inject an unknown injection: 'service:session'.

It turns out, all that was required to resolve the error was to quit and restart the running ember server command. Apparently the live reload server doesn’t include newly installed addons―thanks to a GitHub comment for the hint!

]]>
https://www.munderwood.ca/index.php/2017/03/13/embers-live-reload-server-doesnt-live-reload-addons/feed/ 0
Stacking sections in Laravel Blade templates https://www.munderwood.ca/index.php/2017/02/20/stacking-sections-in-laravel-blade-templates/ https://www.munderwood.ca/index.php/2017/02/20/stacking-sections-in-laravel-blade-templates/#respond Mon, 20 Feb 2017 17:52:19 +0000 http://www.munderwood.ca/?p=153 [Read more...]]]> With Laravel’s Blade templating engine, it is possible to stack multiple sections with the same name throughout a template, and yield them all together in one place. This is particularly useful if you have multiple partial views that each need to append some JavaScript to a  <script> tag at the end of your page, for instance.

tl;dr

Unlike when using the @section  Blade directives, there can be as many @push('name')  directives with the same name as you need. Using the @stack('name')  directive in place of @yield , will then pop them all out at once in a single location in your template (in reverse order).

Example usage

Suppose you’re using jQuery and that you have two partial views that each need a bit of JavaScript to run on page load:

Desired output

<!-- From first partial -->
<div class="must-init">
    <p>Sample</p>
</div>

<!-- From second partial -->
<div class="needs-setup">
    <p>Example</p>
</div>

<script>
    $(function () {
        // Required by first partial
        $('.must-init').initialise();
        // Required by second partial
        $('.needs-setup').setup();
    )};
</script>

Adding the scripts adjacent to the views is problematic, because likely jQuery won’t be loaded when they are executed. You could try to always remember to yield two different sections in the main layout view, but that is rather error prone.

Enter stacks

By stacking the script sections in your views, the same output that you’d create above if you weren’t using partials is easy to achieve. First, @push  the script needed by each view onto the stack:

Partial template one

<!-- From first partial -->
<div class="must-init">
    <p>Sample</p>
</div>

@push('readyscripts')
    // Required by first partial
    $('.must-init').initialise();
@endpush

Partial template two

<!-- From second partial -->
<div class="needs-setup">
    <p>Example</p>
</div>

@push('readyscripts')
    // Required by second partial
    $('.needs-setup').setup();
@endpush

Popping the stack

You can’t use @yield  to insert the pushed scripts into another template, since they weren’t defined in @section  directives. Instead, simply use @stack  in otherwise the same way:

<script>
    $(function () {
        @stack('readyscripts')
    });
</script>

One potentially important caveat to keep in mind is that since this is indeed a stack, the last section that you push onto it will be the first to appear in your rendered output. So instead of obtaining an exact formulation of the code we initially wanted, in this example we’d end up with something like this:

<!-- From first partial -->
<div class="must-init">
    <p>Sample</p>
</div>

<!-- From second partial -->
<div class="needs-setup">
    <p>Example</p>
</div>

<script>
    $(function () {
        // Required by *second* partial
        $('.needs-setup').setup();
        // Required by *first* partial
        $('.must-init').initialise();
    )};
</script>

 

]]>
https://www.munderwood.ca/index.php/2017/02/20/stacking-sections-in-laravel-blade-templates/feed/ 0
Altering PostgreSQL columns from one enum to another https://www.munderwood.ca/index.php/2015/05/28/altering-postgresql-columns-from-one-enum-to-another/ https://www.munderwood.ca/index.php/2015/05/28/altering-postgresql-columns-from-one-enum-to-another/#comments Thu, 28 May 2015 21:40:16 +0000 http://www.munderwood.ca/?p=44 [Read more...]]]> Altering the type of a column in postgres from one enum type to another requires an intermediate cast to  text. Additionally, if there is a default value for the field, it cannot be altered and instead must be dropped and re-added as the new type.

Simple case: New type contains all old-type values

In the simple version, the new enum type contains (at least) all of the same labels as the old one. For instance, as with these two:

CREATE TYPE old_enum AS ENUM ('a', 'b', 'c', 'd');
CREATE TYPE new_enum AS ENUM ('a', 'b', 'c', 'd', 'e');

No default on column

If a table has an old_enum column and we want to turn it into a new_enum one, with no default value in place on the column, we can use the following command:

ALTER TABLE table_name
  ALTER COLUMN column_name
    SET DATA TYPE new_enum
    USING column_name::text::new_enum;

The USING expression casts the current value of column_name to text, and then to new_enum. This works because every allowed value of the first enum type exists in the second.

With a default value

This case is not significantly more difficult to deal with. If there is a default value on the column, we simply remove it before altering the enum type of the column, and then add a new one when we’re done:

ALTER TABLE table_name
  ALTER COLUMN column_name DROP DEFAULT,
  ALTER COLUMN column_name
    SET DATA TYPE new_enum
    USING column_name::text::new_enum,
  ALTER COLUMN column_name SET DEFAULT 'a';

Converting enum labels

A more complicated scenario arises when not all of the old labels appear in the new enum. I’ll assume that there is a mapping from the old ones to the new, at least for every label that is known to appear in a row of the table. If there isn’t, then the conversion is probably not a good idea in the first place.

Consider now an even newer type,

CREATE TYPE newer_enum AS ENUM ('alpha', 'beta', 'c', 'd', 'e');

We still want to convert from the old_enum type, but now we also want to map the label ‘a’ to ‘alpha’, and ‘b’ to ‘beta’, while leaving ‘c’ and ‘d’ alone. This can be accomplished by manually applying each required change via a CASE  statement in the USING  expression:

ALTER TABLE table_name
  ALTER COLUMN column_name DROP DEFAULT,
  ALTER COLUMN column_name
    SET DATA TYPE newer_enum
    USING (
      CASE column_name::text
        WHEN 'a' THEN 'alpha'
        WHEN 'b' THEN 'beta'
        ELSE column_name::text
      END CASE
    )::newer_enum,
  ALTER COLUMN column_name SET DEFAULT 'alpha';

For each record, this statement returns ‘alpha’ or ‘beta’ if the column contains ‘a’ or ‘b’, respectively, or otherwise returns the current value in the column cast as text. The returned value in all cases is then cast to the newer enum type.

]]>
https://www.munderwood.ca/index.php/2015/05/28/altering-postgresql-columns-from-one-enum-to-another/feed/ 13
Arrays of joined ids https://www.munderwood.ca/index.php/2015/05/08/29/ https://www.munderwood.ca/index.php/2015/05/08/29/#respond Sat, 09 May 2015 00:14:41 +0000 http://www.munderwood.ca/?p=29 [Read more...]]]> Thanks to a helpful stack overflow response, I now have an improved solution to my problem of needing to add arrays of joined ids to JSON output from CakePHP 3. The output from a test containing Widget models that can each have many Foos looks something like this:

{
    "widgets": [
        {
            "id": 1,
            "foo_ids": [ 1 ]
        },
        {
            "id": 3,
            "foo_ids": [ ]
        },
        {
            "id": 2,
            "foo_ids": [ 1, 2, 3 ]
        }
    ]
}

 

To easily and automatically add this capability to any model I wanted, I created a new class extending Cake’s  Table , which I called “ApiTable”:

class ApiTable extends Table {
  public function findForApi (...) {
    ...
  }

  public function formatWithJoinedIds (...) {
    ...
  }
}

The  formatWithJoinedIds() method adds an array called  model_ids for each model, from an input list, that is associated with this one through a ‘BelongsToMany’ or ‘HasMany’ join, without including the contents of the associated models. It is intended to be called from the  findApi() method, which simply performs a query containing the passed-in desired list of models and formats the results.

The custom finder is straightforward:

public function findForApi (Query $query, array $includeIdsFor) {
  $query
    ->contain($includeIdsFor)
    ->formatResults([$this, 'formatWithJoinedIds']);
  return $query;
}

The array  $includeIdsFor should contain strings identifying the associated properties whose joined ids should be included. For instance, if a Widget has many associated Foos, Bars, and Bazzes, the ids of the foos and bars would be included in the output by passing  ['Foos', 'Bars'].

The result formatter, used to add the calculated fields containing the id arrays, is a little longer but not much more complicated:

public function formatWithJoinedIds ($results, $keepJoinedData) {
  // Array of all associations this model has many models of
  $joins = array_merge(
    $this->associations()->type('BelongsToMany'),
    $this->associations()->type('HasMany'),
    []
  );
  // Map each result row to itself, with the array id fields
  // added, and optionally foreign model data removed
  return $results->map(
    function ($row) use ($joins, $keepJoinedData) {
      foreach ($joins as $join) {
        $property = $join->property();
        if (isset($row[$property])) {
          // Start a new id array for this property
          $ids = [];
          foreach ($row[$property] as $joinedToRow) {
              $ids[] = $joinedToRow['id'];
          }
          // Turn e.g. 'foos' into 'foo_ids', and add this
          // as a new property of the row
          $row[Inflector::singularize($property) . '_ids'] = $ids;
          if (!$keepJoinedData) {
            // Optionally remove the associated data
            unset($row[$property]);
          }
        }
      }
      return $row;
    }
  );
}

This routine generates an array of all properties of the current model that point to many of another model. It then iterates over these properties, and for each one iterates over all of the foreign models to collect an array of their ids. The resulting array is added as a new property to the row, and the foreign models themselves are unset if they are not to be included in the output.

]]>
https://www.munderwood.ca/index.php/2015/05/08/29/feed/ 0