Using php with Angular 2 and Laravel

I’ve been using Angular 1.0 for the last few projects, but I wanted to get familiar with Angular 2. I found the process of getting up and running with php a bit annoying.

SUMMARY: With php, you can use the ‘5 Minute Quickstart’ tutorial google offers with some adjustments to asset locations, config paths, node packages, and automated tasks (most notably the typescript transpilation process) to get setup with Laravel and Angular 2. Google uses a node app, and a lite node server. I wanted to avoid this and use php and laravel to deploy assets, etc. and use Angular 2. Conceptually:

  1. Make sure you understand which packages you will need. The best would be just to copy the ones from the Angular 2 google tutorial, though not quite all of them will be used (we will let Laravel handle the typescript transpilation).
  2. Make sure you understand where the hell all the files should go. You need to change google’s root level file structure of the example node app to a php laravel app where public assets reside in the nested ‘public’ folder within the root app. Paths in the files need to be adjusted accordingly.
  3. Make sure you understand how to adjust the automated tasks in the gulp file, and in the laravel-elixir-typescript node package. This is mainly about how to get your typescript files to end up in the right place when they are compiled to javascript.

See https://angular.io/docs/ts/latest/quickstart.html

I’ve tried to explain my experience in a way that will make things easier for someone trying to setup any general php app with angular 2 at any point in the near future. The packages, versions, and syntax of the code may vary in the future, but if you understand what changes you need to make conceptually, it will hopefully be easy to use Google’s tutorials and documentation for the next while. My experience was based on the somewhat murky guide at https://www.codetutorial.io/laravel-5-and-angular-2-beta-setup. The video is at https://www.youtube.com/watch?v=dohhsLSbkYA. I found I needed some clarifications on paths, etc. and that the packages used and versions were outdated or unexplained. I tweaked the tutorial found at https://angular.io/docs/ts/latest/quickstart.html. I was using Laravel 5.2.43. I’ve tried to follow the steps in the google tutorial.

Step 1: Create and configure the Laravel and Angular 2 project

I took a laravel project and figured out where to put all the files from the google Angular 2 tutorial. Some files from the tutorial could just go in the root of the app. The following things need to be adjusted:

a) Create a laravel project, and change into that directory. Mine is called laravel_angular2.

laravel new laravel_angular2
cd laravel_angular2

I’ve gotten used to setting up a virtual host and getting the app and and running with php and apache. Hopefully you’ve already made it to this point.

b) Package definition and config files. Copy the typings.json file into the root of your project. Ignore the tsconfig.json file, as we will use laravel an gulp to handle typescript transpiling and serving the app. Put the systemjs.config.js file in the /public folder of laravel. UPDATE THE PATHS in this file to point to / instead of /node_modules, your public folder. The package.json file needs to be merged with existing laravel one. You can essentially copy the dependencies and devDependencies portions of the tutorial package.json file into the package.json file in the root of your laravel app. You can tweak the packages, perhaps remove the lite server and typescript stuff that google includes. As for me, I just left all the packages google indicated in there. I have yet to figure out a good way to determine, when cloning projects, how the hell to figure out which packages are unnecessary, and how to tell which should just go in the devDependencies section when the list gets real long and full of unfamiliar packages. The scripts and other sections of the tutorial package.json can be ignored since, again, we will use laravel an gulp to handle typescript transpiling and serving the app.

c) Install packages. npm install should work fine. Somehow I always screw the packages up and get error messages, but nothing helpful on how to avoid this comes to mind. Hopefully you only get some warnings. I could not get npm run typings install to work, as per the tutorial. I don’t know if this is because we removed it from the scripts section of the package.json file. You can try adding this section and run the command. I suspect it had more to do with the fact that the console wanted a cli package for typings. Do npm install typings --global to get the global cli package, then typings install. We need to deal with the typings folder and move it into public. I didn’t get errors in my quickstart app without moving the typings folder, but it should be moved to the public folder. So, move the ‘typings’ folder into /public. You could probably use a gulp task command to do this. You could also figure out how the hell to adjust google’s code to put this typings folder in public automatically. I never got to that point. The typings.json config file made no sense to me and I don’t know any of the conventions on using that package. I actually don’t even know what the typings folder is used for, but figured it should go in the public folder.

Ignore the ‘Helpful scripts’ section, as we will use laravel and gulp to run the typescript transpiling and the server.

Steps 2-4: Our first Angular 2 component, etc.

Instead of creating an ‘app’ root folder, make a folder ‘/resources/assets/typescript/app’ to house your typescript files. They will be transpiled to the /public/app folder later. Put all the files mentioned in the tutorial in steps 2-4 there.

Step 5.0: Making sure our Angular 2 typescript transpiles using Laravel and Gulp

I couldn’t get google’s typescript transpiler to work easily, and I wanted to use the one included in the laravel packages. The tricky part about this is to avoid jamming on the javascript into a single app.js file. There are 2 ways I’ve done this. The second way is demonstrated in the tutorial on codetutorial.io (and the youtube video), but it involves modifying a node package in the node_modules folder, which is fragile. In my opinion.

  1. Use the gulp typescript library and make a task for transpiling the javascript from typescript.
    var ts = require('gulp-typescript');
    ...
    gulp.task('typescript', function(){
      var assetPath = './' + elixir.config.assetsPath;
      var search = '/typescript/**';
      var options = {
          // If you use ES5, see http://stackoverflow.com/questions/35660498/angular-2-cant-find-promise-map-set-and-iterator
          "target": "ES6",
          "module": "system",
          "moduleResolution": "node",
          "sourceMap": true,
          "emitDecoratorMetadata": true,
          "experimentalDecorators": true,
          "removeComments": false,
          "noImplicitAny": false,
      };
      var outputFolder = 'public';
      return gulp.src(assetPath + search)
        .pipe(ts(options))
        .pipe(gulp.dest(outputFolder))
    });
    
    ... //in the elixir function
        mix.task('typescript', 'resources/assets/typescript/**'); 
    • This is the weird custom step I found useful. It deals with getting the transpiling to work using the npm package elixir-typescript. This involves tweaking the package code, and will not be committed to the git app as it involves editing the node_modules folder. I don’t know if there is a better way to do this, but this idea comes from the aforementioned tutorial. Add the elixir-transcript package. Version 1.1.2: npm install elixir-typescript@1.1.2 I haven’t added this to the package.json file, as we are editing the package manually, but you could add it. Be aware that on certain npm actions, the required update that makes our transpiling work may be overwritten and break.
    • In the file /node_modules/elixir-typescript/index.js, comment out the concat line. //.pipe(concat(outputFileName)). This was on line 28 for me. This is so that when the typescript files are transpiled, they don’t all get mashed into one app.js file. Angular 2 would not like this. Every time you do npm install, you may have to redo this!
    • add the following to your gulp file. The first line was already there for me:<code>

      var elixir = require('laravel-elixir');
      var elixirTypscript = require('elixir-typescript');
      ...
      elixir(function(mix) {
      mix.typescript('app.js','public/app','/typescript/**/*.ts',{
        // If you use ES5, see http://stackoverflow.com/questions/35660498/angular-2-cant-find-promise-map-set-and-iterator
        "target": "ES6",
        "module": "system",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false,
      });

      Run gulp typescript to make sure it works. There should now be javascript files in /public/app. The paths here are weird and took me some tinkering to figure out. More on this later. These 3 steps were definitely the trickiest part of the whole process. It’s more about if you’re keen on learning how to use typescript with your php projects, as similar steps would probably need to be used in any tool that uses typescript on the frontend.

Step 5

Setup the welcome/index/homepage of your Laravel app to load the Angular 2 app. Instead of making an index.html as per the tutorial, update your home view, or whatever you want to run the angular 2 app, to use the html that is in the tutorial. We will need to modify the url paths since the packages used by Angular 2 reside in node_modules folder, which is not in /public. We also need to copy the used packages into the /public folder so we can reference them from the script tags. We will accomplish this by:

  1. Input the html, etc. from the tutorial. In my /resources/views/welcome.blade.php file I added Loading... in the content div. Copy the script tags from the tutorial into the head section.
  2. Add the following commands to the Laravel gulp file in the elixir function:<code>

    mix.copy('node_modules/core-js', 'public/core-js');
    mix.copy('node_modules/reflect-metadata', 'public/reflect-metadata');
    mix.copy('node_modules/zone.js/dist/zone.js', 'public/zone.js/dist/zone.js');
    mix.copy('node_modules/systemjs', 'public/systemjs');

    The following 3 files are also necessary for the framework.

    mix.copy('node_modules/@angular', 'public/@angular');
    mix.copy('node_modules/angular2-in-memory-web-api', 'public/angular2-in-memory-web-api');
    mix.copy('node_modules/rxjs', 'public/rxjs');
  3. Remove references to node_modules from the script includes in your view file. For example, ‘node_modules/core-js’ should just be ‘core-js’. I edited my /resources/views/welcome.blade.php and removed all the ‘node_modules’ from the script tags. The systemjs.config.js file should already be in the public folder from Step 1. Again, note that you should remove reference to the ‘node_modules’ path in this systemjs.config.js.And with that, run gulp, hit your Laravel app’s url,and the quickstart app should load! You’ll probably want to add a gulp task to monitor changes to your typescript. And this is usually the point in a web post where I’m like ‘What the hell, this isn’t working and you seem to be missing some explanations.’ As I think of them, I’ll try and stay current and add in more explanations and pitfalls to avoid this.

TCP versus unix socket sock connection refused failure for php5 fpm and nginx

[error] 13169#0: *7 connect() failed (111: Connection refused) while connecting to upstream, client: XXX.XXX.XXX.XXX, server: test.local, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "test.local"

When setting up nginx to work with php-fpm on ubuntu 14.04, this happened when I was using some config templates from a bit older server. It seems to result from nginx being configured to listen with a socket connection versus TCP, and the virtual host being configured to listen with TCP. The fix was somewhat intuitive, but I never would have thought to look in /etc/php5/fpm/pool.d/www.conf.

The fix for me: In /etc/php5/fpm/pool.d/www.conf, change
listen = /var/run/php5-fpm.sock
TO
listen = 127.0.0.1:9000

This should match the php line in your /etc/nginx/sites-enabled/WHATEVERCONFIG. Mine uses TCP with the line
fastcgi_pass 127.0.0.1:9000;
as opposed to
fastcgi_pass unix:/var/run/php5-fpm.sock;

http://stackoverflow.com/questions/15852884/nginx-connect-failed-error

Prepared statement errors with PHP 5.3 and mysqli. call_user_func_array returns null. Type error?

Prepared statements using mysqli seems to be having issues with PHP 5.3. I kept getting null from a prepared statement command that worked fine in PHP 5.2, namely, the mysqli_stmt_bind_param

Null means that the array you passed didn’t match the function signature.

The following worked in php 5.2, but when I updated my Mac to Snow Leopard (PHP 5.3 included) the following function stopped working

call_user_func_array(‘mysqli_stmt_bind_param’, array($stmt,’isis’,$args));

I kept getting a null return value (note – different than false). See bottom of the following bug:  http://bugs.php.net/bug.php?id=47554&edit=1

"Returns the function result, NULL for an invalid callback, and FALSE
for all other errors."

Toying with the array (translates to method signature of the callback function) passed to call_user_func_array was key. After much head banging (on desk) and much head banging (to music) I found that the following made my one specific test query work:

call_user_func_array(‘mysqli_stmt_bind_param’, array($stmt,’isis’,(int) $args[2],(string) $args[3],(int) $args[4],(string) $args[5]));

I wonder if the library that mysqli uses is in c (so that mysqli_stmt_bind_param is eventually run at a level where typing needs to be determined), and is requiring typed values that the php is screwing up somewhere in the translation. Or on the mysqli level. And I wonder what other explanations there could be for this behavior.

Usually when code is this buggy it is a developer’s coding errors, but someday I hope to run into a bug that isn’t my fault. On second thought, finding a bug in your development language probably causes a lot more pain in trying to figure it out, so I’m not sure that would be much of an accomplishment.