Quick/Easy Laravel/Docker

Source: https://hub.docker.com/r/bitnami/laravel

Commands:

cd toys (projects folder)

mkdir saml && cd saml (a bare saml project)

curl -LO https://raw.githubusercontent.com/bitnami/bitnami-docker-laravel/master/docker-compose.ymlcurl -LO https://raw.githubusercontent.com/bitnami/bitnami-docker-laravel/master/docker-compose.yml

docker-compose up

Connect to the dev server over SSH in vscode and access at http://devserver:3000/

A blog for Emmett

It may come back to bite us. I made Emmett a WordPress blog tonight, a new outlet for his creative energy that so far is spent on long term minecraft trap strategies.

He’s 6, and it’s hard to find productive outlets for him. He gets tunnel vision about a single project at any one time.

So far, he’s added a post about home schooling and a general images post. I hope it consumes him like Minecraft does.

Emmett from Bargo’s blog.

Nuxt.js – redirect

The router docs are a little bit muddy with redirects.

Push the new route onto the stack to redirect.

this.$router.push(`/users/${id}`)

Replace the route on the stack to replace in the browser.

this.$router.replace(`/users/${id}`)

Extra: Updating querystring

Changes the querystring in the URL bar to match the filters parameter.

Uses ‘replace’ to save polluting the back history (I hate that so much!)

        this.$router.replace(
          { path: this.$route.path, query: this.filters },
          e => {}
        )

Laravel – re-assign relationships in updates

Alternate title: Stop stuffing around with entity_id.

Working on a project with a representative – a user who looks after the company.

When changing the representative, I want to supply the whole representative to the update method – e.g. $customer->representative is an object with an id, name, etc. It’s just a pointer, but it means less double handling to send in the object.

I do not want to extract the ID from the object that the user supplied and pass that to the controller.


In the Company model, we need a ‘setRepresentativeAttribute’ method. This extracts the ID and puts it in the representative_id column.

    public function setRepresentativeAttribute($value)
    {
        $this->attributes['representative_id'] = $value['id'];
    }

Instead of making sure representative_id is fillable, we now need to make sure representative is fillable on the model.

protected $fillable = ['representative']; //not representative_id

It’s a simple pattern, but also one I’ve implemented the long way in the past.

Vue.js – mapGetters with Params

Using mapGetters with parameters isn’t well defined in the docs, and is a pattern I go to use pretty regularly.

I never find a good search result, so here goes:

1.Define the getter in the store. Take note that the naming convention will be [store namespace]/[getter name] later. Since this is in my users store, it’ll be users/usersForMember. Note the function accepts a parameter.

  usersForMember: (state) => (member) => {
    return state.users.data.filter(u => u.member_id === member.id)
  }

2.Connect the component side getter to the getter in the vuex store. I kept trying to mangle mapGetters to accept my params. This is the wrong approach – it just need to be directly wired up. Note the [namespace]/[getter name] convention from above, so vue can find the getter.

  
import { mapState, mapGetters } from 'vuex'

/* snip */

computed: {
    ...mapState({
      // other stuff
    }),
    ...mapGetters({
  // this is it.
      usersForMember: 'users/usersForMember'
    }),

Now, the piece I always miss! Write a method in the component to call the getter with the parameter.

  computed: {
    /* snip, from above */
// this is it:
    users () {
      return this.usersForMember({ id: this.user.member_id })
    }
  }

Over in the template, we can now output {{users}} and see the results of our handywork.

VueX Patterns: Updating in Array

When working on a type of entity, it’s common to post the new or updated entity to the server and then need to update it in the local vuex data store.

This is a simple pattern that propagates the changes to the UI displaying the list of entities.

1. Save the entity, from the UI.

 this.$store
          .dispatch('catalogs/create', {
            catalog: this.user
          })

2. POST the entity to the server in a vuex action, and pass the response to a mutation.
Note we also return the response data, in case the UI needs it for a flash message.

 async create (context, { user }) {
    const responseUser = await this.$axios.$post('users', user)
    context.commit('userFetched', responseUser.data)
    return responseUser
  },

3. Replace the object in array if it already exists. If it doesn’t exist, push it to the bottom of the array. Clone the array to trigger a UI update.

  userFetched (state, user) {
    const existsAtIndex = state.users.data.findIndex(u => u.id === user.id)

    if (existsAtIndex !== -1) {
      state.users.data[existsAtIndex] = user
    } else {
      state.users.data.push(user)
    }

    state.users.data = [...state.users.data]
  }

4. The UI which lists these users (UserRow below) will update itself with the new entry.

 computed: mapState({ users: state => state.users.users }),
<UserRow v-for="user in users.data" :key="user.id" :user="user" />

Solar in Bargo – numbers

We installed solar at our house in Bargo 2574 (a town in Wollondilly, NSW) in March 2020.

It cost approximately $5k for a 6.5kW system (feeding into a 5kW inverter). Half the panels face west, and half face north.

I’ve always been concerned that people who install solar need to convince the world that it was a good decision, and they often mask the real numbers involved. With that, here’s some real numbers.

A few interesting points, after a week of ownership.

A sunny day in Summer generates >30kW ($9 of electricity). The effective timespan is 8:30am (~1kW) until 6pm (~1kW). From 11am until 4pm the system generates consistently generates between 4-5kW. The highest I’ve seen is just slightly over 5kW, so I assume it maxes out there.

A gloomy day, raining from sunrise to sunset is generating ~5kW max for the day. ($1.50 of electricity)

Our usage (6 person household, 3 x split system air conditioners, tvs left on, 2x fridges, always using a dryer, and a pool) is 30-40kWh/day ($9-12 of electricity per day). This means on the sunny days we’re generating as much power as we’re using.

Unfortunately, the feed-in payment will be 10c/kW (where it costs ~30c/kW to consume) so we expect that even with perfect summer days we will still generate a bill*.

I’m not sure what our day/night consumption is like relative to the solar power generation window of 8:30-6pm, and obviously those goalposts will continue to move after summer. We’re expecting a 30-40% drop on our electricity bills and a 2 year repayment window on the $5k outlay.

*At the moment, our power meter (that is read manually every 3 months) cycles backwards when we are generating excess power. Wish we could leave it that way, it’s effectively 30c/kW feed-in payment too! I have a feeling the energy company won’t waste time fixing that.

I’ll follow this up when we receive our next power bill. The solar system was installed the day after our quarterly bill rolled over, so we should get a very realistic number on what we’ve saved.

Vue.js fragments

All manner of googling didn’t turn up a good result for this problem.

Sometimes, you need a wrapper component with logic attached that does not render to the UI.

For example, child components with a percentage of the parent can’t just have a div wrapped around them for conditional logic.

Another example (which I found a different, novel solution for) is using more than one child component in a root node. Only one renders, but a few are there and are excluded by logic.

React has a ‘fragment’ for this and afaik vue.js does not.

Using ‘vue-fragment’ adds a helpful fragment tag that is removed during render, but allows application of logic and generally acting as a ‘root’ component for multiple siblings.

below, we are using a ‘fragment’ tag to render or hide 2 items based on if the user is an admin. Trivially wrapping these in a div with logic breaks the layout.

                <b-navbar-nav>
                    <b-nav-item :to="'/'">
                        Dashboard
                    </b-nav-item>
                    <b-nav-item :to="'/something'">
                        Something
                    </b-nav-item>

                    <fragment v-if="user.role === 'Admin'">
                        <b-nav-item :to="'/item-1'">
                            Item 1
                        </b-nav-item>
                        <b-nav-item :to="'/item-2'">
                            Item 2
                        </b-nav-item>
                       
                    </fragment>
                </b-navbar-nav>

Install from yarn (or npm i vue-fragment)

yarn add vue-fragment

Add the fragment component

import { Plugin } from 'vue-fragment'
import Vue from 'vue'
Vue.use(Plugin)
<fragment>
  <div>Use the fragment! The fragment tag will be removed at render time.</div>
</fragment>

Nuxt.js Mixin – access global property in template

Adding a mixin in nuxt.js is just like adding a plugin. For my project, I needed a date format property set once but accessible in all my templates (named ‘moment_format’)

Step 1, In plugins/, create a plugin file (Mine is called ‘vue-format-global.js)

// plugins/vue-format-global.js
import Vue from 'vue'

var mixin = {
  data: function () {
    return {
      moment_format: 'DD/MM/YYYY HH:mm'
    }
  }
}

Vue.mixin(mixin)

Step 2, connect up the plugin in nuxt.config.js

  // in nuxt.config.js

  /*
  ** Plugins to load before mounting the App
  */
  plugins: [
    /* other plugins ... */
    '~/plugins/vue-format-global'
  ],

Step 3, restart the app and use freely in your templates.

// inside a template
<template>
effective since {{data.effective_date | moment(moment_format)}}
</template>

Nuxt.js and Vuex – dumping flash messages

Context:

  • A child component has received an error message, and needs to communicate it to the parent layout.
  • There’s no unhacky way to do that, so we should put it in the application store (vuex).
  • When the user navigates, the error is retained forever more.

It’s a problem seemingly without a clean answer.

Step 1: In the vuex store, create an errors array to hold the errors. Create two mutations: ‘set_errors’ and ‘clear_errors’.

// store/index.js
export const state = () => ({
  errors: []
})

export const mutations = {
  errors (state, errors) {
    state.errors = errors
  },
  clear_errors (state) {
    state.errors = []
  }
}

Step 2: In the component generating the error, put the errors in the vuex store.

// sign in has failed.
.catch(e => {
        let errors
        switch (e.response.status) {
          case 422:
            errors = this.translateErrors(e.response.data.errors)
            this.$store.commit('set_errors', errors)
            break
        }
      })

Step 3: In the ‘Errors’ component that lives in the layout, capture and display the errors. Confirm these two pieces are communicating.

// components/Errors.vue

<template>
    <div>
      {{errors.map(e => e)}}
    </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  computed: mapState(['errors'])
}
</script>

If that’s all working, it’s time to clear the message between navigation events.

Step 4: Create a ‘clearFlash’ middleware.

// middleware/clearFlash.js

export default function (context) {
  if (context.store.state.errors.length > 0) {
    context.store.commit('clear_errors')
  }
}

Step 5: Wire up the middleware in nuxt.config.js. Add the router and middleware keys if needed.

//nuxt.config.js

  router: {
    middleware: 'clearFlash'
  },

All done and working!