Optimal PHP Development IDE

So, I wanted to share my php development environment.

The setup is :

Next we download Xdebug which gets attached to PHP via php.ini – download here

I’m using the PHP 7.4 VC15 TS (64 bit) (Latest at the moment) —

 

 

Vuex Basics

So Vuex is very similar to Redux as far as what they are trying to accomplish. It is about creating a data store that all components can access rather than passing the data directly from component to component.  These are my quick notes on Vuex.

Creating a Store


const store = new Vuex.Store ({
    // The data we want available to rest of application
    state: {
        message: 'Hello World',
        count: 0
    },
    // These are things that change the state // synchronous
    mutations: {
        increment(state,payload){
            state.count+=payload;
        }
    },
    // Asynchronous
    actions: {
        increment(state,payload){
            state.commit('increment',payload)
        }
    },
    // These are a central way to pull data from the state
    getters: {
        message(state){
            // Formatting it for example
            return state.message.toUpperCase();
        },
        counter(state){
            return state.count;
        }
}
});

Grabbing the data from the store (Not Recommended)

Although you can do this to grab the data directly from the store – its better to use the getter. That way if you implement formatting/validation etc it can be done in one place.

Script


<script>
new Vue ({
    el: '#app',
    data() {
        return {
            welcome: 'Hello World'
        }
    },
    computed: {
        message(){
            return store.state.message;
        }
    }
})
</script>

Output (html/razor)


 <body>
        <div id="app">
        <h1>{{welcome}}</h1>
        <h2>{{message}}</h2>
        </div>
    </body>

Grabbing the data from the store using a getter
Script


<script>
new Vue ({
    el: '#app',
    data() {
        return {
            welcome: 'Hello World'
        }
    },
    computed: {
        message(){
            return store.getters.message;
        },
        count(){
            return store.getters.counter;
        }
    },
    methods : {
        pressed(){
            // Would call the mutation (synchronously)
            //store.commit('increment',10);
            // This calls the action (Asynchronously)
            store.dispatch('increment,10);
        }
    }
})
</script>

Output (html/razor)


 <body>
        <div id="app">
        <h1>{{welcome}}</h1>
        <h2>{{message}}</h2>
        <h3>{{count}}</h3>
        <button @click="pressed">Increment Counter</button>
        </div>
    </body>


Some Final Thoughts

  • Actions are async meaning that all API requests should be done in actions. Vue Docs – Actions
  • Mutations are synchronous – so these should not require any outside resource ever. Pure state manipulation only.
  • Recommended App Structure for Vue Apps

Vue Toes in first!

So one of the upcoming projects I am working on let me know they use Vue. I decided to get a headstart on things and dip my toes into the Vue pond!

First I want to give thanks to Brad @  Traversy Media for his Vue JS Crash Course video.
These are my notes from the video as well as my first experience with Vue.

Breaking Down a Vue Component

These break out into basically three different parts.

  • (HTML) Output which is basically a blade/razor/twig template/etc page.
  • (JS) Functionality this is the data retrieve/load/manipulate/delete (CRUD) layer, animation
  • (CSS) Style which includes formatting for the component

Output

   <template>
        <div class="user">
            <h1> {{ user.name }} </h1>
        </div>
    </template>

 

Function

 <script>
        export default {
            name : 'User',
            data() {
                return {
                    user: { 
                        name: 'Brad'
                    }
                }
            }
        }
    </script>

Style

 <style scoped>
    h1 { font-size: 2rem;} 
 </style>

 

Getting Setup – Environment

You need

From Command Prompt

Install Vue CLI (Command-line interface)

npm install -g @vue/cli

 

Create your project

vue create test

*test is the project name – this can be whatever you want

 

 

Code Bits

Example functionality that has data

<script>
import Todos from './components/Todos.vue';

export default {
    name: 'app',
    components: {
        Todos
    },
    data() {
        return {
            todos: [
                {
                    id:1,
                    title:"Todo One",
                    completed: false
                },
                {
                    id:2,
                    title:"Todo Two",
                    completed: false
                }
            ]
        }
    }
}

Now to use that loaded data and pass it to the output we would use a Vue attribute v-bind
<template>
    <div id="app">
        <Todos v-bind:todos="todos" />
    </div>
</template>

Receiving data in a component

So now the Todos component when its loading we can receive the data the same was as React. This means we grab it out of the properties passed to it – stored in props.

<script>
export default {
    name: "Todos",
    props: ["todos"]
}
</script>

Output Template For Todos Component
Then to print out each of the data

<template>
    <div>
        <div v-bind:key="todo.id" v-for="todo in todos">
        <b>{{todo.title}}</b>
        </div>
    </div>
</template>

Now the two key parts to the above.

  • v-for=”todo in todos” which is what is iterating thru the data passed in from props
  • v-bind:key=”todo.id” which sets the unique key for the data – so id in this case. Vuetr (Visual Studio Code Addon) will give you a syntax error if you do not include the unique key – best practice kinda thing.

So in the video he broke the Todos (list of todo) into TodoItem component. There was a neat trick in there about binding on a conditional.

<div class="todo-item" v-bind:class="{'is-complete':todo.completed}">

So lets break that down abit.  The v-bind:class attaches the css class “is-complete” whenever the statement to the right of the colon is true.  So in the data he has a true/false in todo.completed so this already directly goes to a boolean.

 

Event Handling 

<input type="checkbox" v-on:change="markComplete">


<script>
export default {
    name: "TodoItem",
    props: ["todo"],
    methods: {
        markComplete() {
            this.todo.completed = !this.todo.completed;
            console.log("show mark completing");
        }
    }
}

So breaking this down.  the v-on:change=”markComplete” adds the js event listener for onChange  and invokes the method markComplete.

This is how to add methods to a component.

Bubbling up an event

So in TodosItem

<button v-on:click=”$emit(‘del-todo’,todo.id)”>x</button>

So this is running in the todosItem – so its really in 2 parts.

‘del-todo’ which is the name of the event, and the second todo.id is the paramaters you want to pass to it.

 

Then in Todos (the list of todos)

<TodoItem v-bind:todo=todo v-on:del-todo=$emit(del-todo, todo.id) />

This catches the event and fires the event to the parent.

In the parent we can catch that and fire a method

v-on:del-todo=”deleteTodo”

 

Brads completed source code is available at Github

Thanks again Brad! Very Helpful!

Here is Vue’s documentation Vue Docs

Next I’ll need to get exposed to Vuex which is a state manager similar to redux (used with react).

 

 

 

Front End Testing Using Selenium

So I’m sitting down at the local technology hub in downtown aka the Barn Light ready for the Code for America meetup and I find I have a moment to write up a short bit about doing front end testing. This seems to be the last kind of testing anyone ever makes it to. Most people get to the unit testing in their application but the testing from the user side in is often overlooked.

So what is front end testing web applications? This means testing it from the user’s perspective in the browser. Loading the content, clicking the buttons, widgets or other interactive material and then asserting that a certain behavior or result will occur. Its the same as back end testing, but in the browser.

So lets start with a really simple test – we’re going to load the main page – we’re then going to load the about page – and then if “about” is on the page – it passes.

If the test is green (which this one is) then its success.. If its a failure then it would be red.
We can use this in more advanced tests to test deep functionality.

This next test goes from the main page and searches for “on linux” then clicks on the first post and looks to see if a known phrase is in the first page. This is testing submitting the form to the search and getting a result on a known datasource.

Hack 4 a Cause – Eugene,OR

So this last weekend I participated in grand daddy of Eugene,OR hackathons called Hack for a Cause.  There were over 80 participants and a large rush of support staff to assist with food, snacks, design, story, mentoring and more.  The wide variety of contributors ranged from multiple masters degrees to south lane robotics high school team!  The only thing that didn’t vary was the positive mood.  The high energy, all excitement gung ho, good to go, feel good vibes were seen in every smile and conversation.  There was basically was a cyber army ready to dive in and do something that will have some positive impact on the world around us.

My experience with hackathons is that the first day of a hackathon is all about taking abunch of different ideas from a newly formed team and creating a cohesive  vision.  The team I joined was the Oregon Campaign Trail, which is the brain child of Jim Cupples. I’ll let him introduce the project you.

 

 

Oregon Campaign Trail Team

Developer

  • Daniel Coat
  • Jacob Groff
  • Jeremy King
  • Robert Moore
  • Tucker Matias

Story

  • Annie Heckel
  • Kris McAlister
  • Jim Cupples

Story/Developer

  • Eric Reynolds

Designers

  • Matt Bliss
  • Whitney Farrell

 

After the event I was invited to speak on the Tech Tuesday to talk about the hackathon and my thoughts on it with Joshua Evans.

 

Game Jam 2019 Recap

So this year was my first game jam! First off, thanks to Pipeworks for providing the venue! This was a great spot to do the event and I’m looking forward to future jams! The event gathered 50+ developers ranging in skills between programming, audio, graphics and system design.  Participants registered and received a name badge that had a sticker to represent each of their chosen specialties.  I snagged a red dot for programming! (Huge surprise right?)

Ted Carter a developer from Pipeworks went out of his way to make everyone feel comfortable in the space. There was a good mix of introvert/extrovert and I feel like he bridged the gap well!  A welcomed appearance by local tech community leader Mark Davis  brought some awesome catering from Baja Express! (Thanks!) Also Thanks to Nikole Gipps for dishing out the Badgr Badges for the Game Jam!

 

 

But what about all the games? Heres the link! https://globalgamejam.org/2019/jam-sites/igda-eugene/games  There were 13 different games created at the Jam.  There were also some great multiplayer concepts that I had not run across before. There were a couple of 2 player games, where the two players had to complete an objective like to meet up with eachother or a common place.  As the players got close to each other the field of view would increase! Very Cool!

 

What did I do? My team decided to make a game in HTML5 canvas JS using webpack. Source code @ https://github.com/bobby5892/InterstellarHomeRunDerby  and if you want to test your skill its available for play at https://eugeneprogramming.com/gamejam.


Good fun!

First View Flutter – Quest for Hello World

Flutter is a new cross platform language allowing you to release IOS/Android apps.

I hit up the download page at https://flutter.io/docs/get-started/install/windows and downloaded the flutter_windows_v1.0.0-stable.zip.

I moved it to C:\flutter



Ran “flutter_console.bat” as Administrator


Ran “flutter doctor” and it looks like i was missing some things.

So first I decided to add flutter into my environment path for windows (windows 10)

Open Control Panel -> all Control Panel Items -> system -> advanced system settings -> Environment Variables

Then select Path and edit.


Then New and type C:\flutter\bin


Hit ok to save.

Now when I open a new command prompt window I should be able to run flutter from anywhere.

Cool so that part works!


Ok so now that its installed and added to path, I decided to fix those “flutter doctor warnings/errors”.


Ran flutter doctor –android-licenses and spammed Y for yes like 5x.


Then in android studio when you open it I clicked the gear at the bottom labeled configure and plugins typed “flutter” and then search in repositories.


Clicked Install – it installed real quick … Restart android studio and then do

it again but type “dart” in the box and installed that as well. It restarted android studio. (don’t do both at once – otherwise it just does the second one)

I then went back to command prompt to run the flutter doctor again to see if i had resolved everything.


So great! I feel like i’m really ready to start the hello world.

so then I did “flutter create hello_world” and it created a directory and some starting files.


In android studio I went to open the project. It had a cool little icon for the project folder.

When it opened it had some pre code there – so I changed it to say Hello World

When i went to build/run it said “No connected devices found; This makes sense why I saw that when the flutter doctor ran!

I went to https://flutter.io/docs/get-started/install and after reading it found out there was nothing i needed to install.

I then found I had to goto Tools -> AVD (Android Virtual Device Manager and download an android device SDK



I hit the download link. It was 750mb.

Once it finished downloding i was able to run it




When I ran the flutter doctor – it showed all 4 as green checkmarks! I figured I was ready to build/run! So i hit build!

Oh sweet success!

.Net Core on Linux

Host ASP.NET Core on Linux with Apache

Server Config
# install apache / bind

yum install bind httpd

# create link to Maria DB Repository

vi /etc/yum.repos.d/MariaDB.repo

#paste this in

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

#install it

yum install mariadb

#add .net core feed

rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm

#update all existing packages

yum update

#install .net core 2.2

yum install dotnet-sdk-2.2 -y

#add a user for asp projects

adduser asp-dev
Passwd asp-dev

#add user to wheel adds su priv

usermod -aG wheel asp-dev

#switch to asp-dev user

su asp-dev

#goto home folder

cd ~

#make aspTest project

dotnet new console -o aspTest
cd aspTest

#create Program.cs

vi program.cs

Then paste

using System;

namespace myApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Type :wq to save
Then test it with

dotnet run

Should look like

#switch back to root

su root

#start mariadb

service mariadb start

#force mariadb to start each time the system boots

systemctl start mariadb

#start named (DNS)

service named start
system start named

#create Zones folder for DNS

mkdir /etc/named/zones

#create zone for eugeneprogramming

vi /etc/named/zones/eugeneprogramming.com

Paste

; BIND db file for eugeneprogramming.com

$TTL 86400

@       IN      SOA     lee.ns.cloudflare.com.      hostmaster.eugeneprogramming.com. (
                        2019011901	; serial number YYMMDDNN
                        28800           ; Refresh
                        7200            ; Retry
                        864000          ; Expire
                        86400           ; Min TTL
			)

                NS      lee.ns.cloudflare.com. 
                NS      amanda.ns.cloudflare.com. 

                MX      10 mail.eugeneprogramming.com.
                MX      20 mail.eugeneprogramming.com.


$ORIGIN eugeneprogramming.com.

Then :wq to save

#edit named.conf to include zone

vi /etc/named.conf

#Add to end

zone "eugeneprogramming.com" IN {
        type master;
        notify no;
        file "/etc/named/zones/eugeneprogramming.com";
};

#Create public_html folder

mkdir -p /var/www/eugeneprogramming.com/public_html
chown -R eugenep:eugenep /var/www/eugeneprogramming.com/public_html
chmod -R 755 /var/www

#create apache sites-available

mkdir /etc/httpd/sites-available
mkdir /etc/httpd/sites-enabled

#edit apache config

vi /etc/httpd/conf/httpd.conf

#add to end

IncludeOptional sites-enabled/*.conf

#link it to enabled

ln -s /etc/httpd/sites-available/eugeneprogramming.com.conf /etc/httpd/sites-enabled/eugeneprogramming.com.conf

#make ssl folder

Mkdir /var/www/eugeneprogramming.com/ssl

#generated origin SSL cert in cloudflare PEM Format

#Create a .crt file and a .key file from cloudflare and save it in ssl folder

#Then in the vhosts

SSLEngine      on
SSLCertificateFile        /path/to/your_domain_name.crt
SSLCertificateKeyFile     /path/to/your_private.key 

#edit your vhost and add it all in

vi /etc/httpd/sites-available/eugeneprogramming.com.conf

#at the end of everything it will looklike

So part of this is a reverse proxy that passes the local application running on port 5001 to an apache subdomain.

#create Maria DB and user

Type MYSQL and a terminal prompt shows
create database eugenepr default character set utf8 default collate utf8_bin;

This is an admin user with access to all databases

CREATE USER 'bar'@'%' IDENTIFIED BY 'strongpassword';
GRANT ALL PRIVILEGES ON *.* TO 'bar'@'%' ;

You can limit to a database like eugenepr

GRANT ALL PRIVILEGES ON eugenepr.* TO 'bar'@'%' ;

#I like phpmyadmin so i added that

rpm -iUvh http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install phpmyadmin
vim /etc/httpd/conf.d/phpMyAdmin.conf

#Add your ip to allowed
#also add your connection settings

Application Specific Changes
In your ASP Core project install Pomelo.EntityFrameworkCore.MySql Nuget package. I did version 2.1.4.

Then in your startup.cs

 // Msql 
 // services.AddDbContext(options => options.UseSqlServer(Configuration["ConnectionStrings:Local"]));

Change To

 // Maria DB
      services.AddDbContext(options => options.UseMySql(Configuration["ConnectionStrings:Local"]));

Then your appsettings.json connectoin string is going to change to be

"Local": "Server=127.0.0.1;Database=YOURDATABASE;User Id=YOURUSER;Password=YOURPASSWORD"

Creating a Service of your App

In order for your app to run all the time you need to create a service

vi /etc/systemd/system/lab2.service

Put this in and save

[Unit]
Description=Lab 2 for CS296

[Service]
WorkingDirectory=/var/www/eugeneprogramming.com/cs296/lab2
ExecStart=/usr/bin/dotnet run /var/www/eugeneprogramming.com/cs296/lab2
ExecStop=/usr/bin/pgrep dotnet-cs296-lab2
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-cs296-lab2
User=eugenep
Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]
WantedBy=multi-user.target

Now you should be able to

service lab2 start

And just so its the default for the system to start the service on boot

systemctl start lab2

If all is well you should be able to access your .net core app via apache reverse proxy 🙂

C# Xunit Mocking Db Context (For Testing)

So in my App I use Repositories like.

 public class CommentRepository 
    {
        AppDBContext context;

        public List Comments { get { return this.context.Comments.ToList();  }  }
        public CommentRepository(AppDBContext context)
        {
            this.context = context;
        }
}

The AppDbContext inherits DbContext (part of Entity Framework).

Then in the startup.cs in the ConfigureServices method I add
services.AddDbContext(options => options.UseSqlServer(Configuration["ConnectionStrings:Local"]));

Ok ok... So on to testing.

In my xUnit testing project, with a reference to the main project I can then do a Mock Context and do a database in memory.

Full Example

public class ComplaintTests
    {
        public AppDBContext Context { get; set; }
        public ComplaintRepository ComplaintRepo;
        
        public CommentRepository CommentRepo;

        public ComplaintTests()
        {
            
            /* Create a Memory Database instead of using the SQL */
            var optionsBuilder = new DbContextOptionsBuilder()
                .UseInMemoryDatabase(databaseName: "temp")
                .Options;
            Context = new AppDBContext(optionsBuilder);
            ComplaintRepo = new ComplaintRepository( this.Context);
            CommentRepo = new CommentRepository( this.Context);
        }
    
        
        
        [Fact]
        public void TestTesting()
        {
            //Test that testing is working
            Assert.True(true);
        }
        [Fact]
        public void AddComplaint()
        {
            Complaint complaint = new Complaint() { ID = 1, 
            Contents = "Test Complaint", Completed = false, Create = DateTime.Now };
            bool success = ComplaintRepo.AddComplaint(complaint);
            Assert.True(success);
            // Cleanup
            Context.Database.EnsureDeleted();
        }

A great way to do testing!

More info at Microsoft C# Core In Memory Testing

Using Android Device Monitor in Visual Studio to access locked folders

First you have to have your android emulator running

Then to open up the Android Device Monitor you click on the icon on the icon in visual studio

When it opens up it should look like

The Problem

When I click the icon next to data to look at the user data, I can’t see it because my device is not rooted. In order to get around this so I can verify file creation in my current development process. I force the ADB (android development bridge) to run as root.

So I open a command prompt via the toolbar and type adb root

Now when I view the folder in Android Device Monitor I can see the locked folder

Now there may be security concerns that I’m not aware of that make this a bad idea. The scenario for me that I need to do this is to verify that a file is created during my initial Android Applications activity is supposed to generate in the personal folder for the app.

ASP Core C# Entity Framework Cheat Sheet

Step 1) Create Models – example

namespace Project.Models{
	public class Product{
		public int ID { get; set;}
		public string Name { get; set;}
		public string Description { get; set;}
		public decimal Price { get; set;}
		public string Category { get; set;}

	}
}

Entity framework looks for properties with ID in it and makes that the primary key.
Step 2) Create Repository – example

using System.Collections.Generic;
using System.Linq;
namespace Project.Models {
 public class ProductRepository : IProductRepository {
 private ApplicationDbContext context;

 public ProductRepository(ApplicationDbContext context) {
 context = context;
 }
 public IQueryable Products => context.Products;
 }
}

Step 3) Create a Database Connection string and add it to appsettings

{
 "Data": {
 "Project": {
 "ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=ProjectDB;Trusted_Conne
ction=True;MultipleActiveResultSets=true"
 }
 }
}

Step 4) Add DB Context as a service

Open Startup.cs
Look for the method

public void ConfigureServices(IServiceCollection services) 

Then add

services.AddDbContext(options =>
 options.UseSqlServer(
 Configuration["Data:Project:ConnectionString"]));
 services.AddTransient();

Step 5) Disable Scope Verification

Edit Program.cs

Look for

public static IWebHost BuildWebHost(string[] args) =>
 WebHost.CreateDefaultBuilder(args)
 .UseStartup()
 .Build();
 }

Change to

public static IWebHost BuildWebHost(string[] args) =>
 WebHost.CreateDefaultBuilder(args)
 .UseStartup()
 .UseDefaultServiceProvider(options =>
 options.ValidateScopes = false)
 .Build();
 }

Step 6) Database Migration

Open command prompt within the project folder (that contains your .sln)
Type

doetnet ef migrations add Initial
dotnet ef database update

C# Newtonsoft JSON Serialize and Deserialize of Objects

So after abit of headache. I figured out how to serialize nested objects and deserialize them. This is especially useful for doing Android Development with C#.

So for starters!

Here are the Objects/Models

public class Game

      public class Game
    {
        public Player currentPlayer;

        public Player player1;
        public Player player2;
        public Die die;
        public int currentRound;
        public bool canRoll;
        public bool gameOver;
        public Player winner;
}

public class Player

 [JsonObject(MemberSerialization.OptIn)]
    public class Player
    {
        [JsonProperty("Name")]
        public string Name { get; set; }
        [JsonProperty("Score")]
        public int Score { get; set; }
        [JsonProperty("FinalRollComplete")]
        public bool FinalRollComplete { get; set; }
    }

So the [JsonObject(MemberSerialization.OptIn)] is optional when everything is public. However if I had a protected class I would need it and the JsonProperty in order to store it in my json string.

 public class Die
    {
        [JsonProperty("currentValue")]
        public int currentValue;
}

Ok so now you know the setup, lets talk about the actual serialize and deserialize.

Serialize

string json = JsonConvert.SerializeObject(this.Game, Formatting.Indented);

Deserialize

 Game = JsonConvert.DeserializeObject<Game>(json);

So this also requires you install the NuGet package for Newtonsoft.Json and add the

using Newtonsoft.Json;

at the top