Monthly Archives: January 2020

How to use the Amazon AWS SDK for Textract with PHP 7.0 Asynchronously

A few days ago, I got an interesting question about my post which describes using the Amazon AWS SDK for Texttract. The question was “How can I d this with a PDF stored in S3? I know you need to use analyzeDocumentAsynch but unsure how to then get the results of the Asynch operation“.

It turns out to be pretty easy, once you’ve got the synchronous example running. The synchronous Textract example is described in that previous blog post.

Here are the code changes you need to make. Keep all the source code as before, but starting with the call to analyzeDocument, replace that and the following lines with this code:

$promise = $client->analyzeDocumentAsync($options);
$promise->then(
    // $onFulfilled
    function ($value) {
		echo 'The promise was fulfilled.';
		processResult($value);
    },
    // $onRejected
    function ($reason) {
        echo 'The promise was rejected.';
    }
);

// If debugging:
// echo print_r($result, true);
function processResult($result) {
	$blocks = $result['Blocks'];
	// Loop through all the blocks:
	foreach ($blocks as $key => $value) {
		if (isset($value['BlockType']) && $value['BlockType']) {
			$blockType = $value['BlockType'];
			if (isset($value['Text']) && $value['Text']) {
				$text = $value['Text'];
				if ($blockType == 'WORD') {
					echo "Word: ". print_r($text, true) . "\n";
				} else if ($blockType == 'LINE') {
					echo "Line: ". print_r($text, true) . "\n";
				}
			}
		}
	}
}

When you run your PHP code from the command line, you’ll notice a small wait while the asynchronous code processes, and then you’ll see the same output as before.

Here’s a link to the Guzzle Promises project to give you an idea of how to use Promises in PHP.

And here’s the full source example use of analyzeDocumentAsync.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to add a select element in React Native

TL;DR: The React Native Picker component is the equivalent of the HTML select element.

In my last post, I used fetch to download a list of movie titles. However, I only displayed the list by using a debugging tool. My app user will want to see this list, and even better, may want to select something off the list. The commonly used web widget which does this is the HTML <select> element. In React Native, the corresponding widget is a Picker.

You can add a Picker to your render method very easily, like this:

import { Picker } from 'react-native';
...
render() {
    return <View>
        <Picker>
        </Picker>
    </View>;
}

That’s a start, but it doesn’t display my data, and it doesn’t look very interesting. We’ve got a picker with no functionality which looks like this:

Notice the little upside-down triangle in the upper right corner, which indicates the Picker has loaded.

In order to populate the Picker with data, we need to get access to the list of movies inside the render method. Fortunately, I already used setState to make the movie data persist in my app’s state (see previous post). That means I can use it in render, like this:

render() {
    let items = [];
    var length = this.state.dataSource.length;
    for (var i = 0; i < length; i++) {
        var item = this.state.dataSource[i];
        // Really, really important to not put quotes around these braces:
        items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
    }
    return <View>
        <Picker>
        </Picker>
    </View>;
}

Uh oh, wait, as soon as I added this code, I saw the red screen of death in the emulator. The error message read “TypeError: null is not an object (evaluating ‘this.state.dataSource’). This error is located at: in HelloWorldApp (at renderApplication.js:40)…”

The problem is that I tried to reference this.state.dataSource before it had been set. The render method might be called before fetch runs. We don’t know when our fetch statement will be called, or even if it is successful. We need to add code in render which handles the case where this data is not yet available.

Here’s the new render code which skips doing anything with dataSource if it is not found:

render() {
    if (this.state && !this.state.isLoading) {
        let items = [];
        var length = this.state.dataSource.length;
        for (var i = 0; i < length; i++) {
            var item = this.state.dataSource[i];
            items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
        }
        return <View>
            <Picker>
            </Picker>
        </View>;
    } else {
        return ( <View></View>);
    }
}

That fixes the error, but the Picker is still empty. But in anticipation of needing a list of movies, I’ve already got a list of Picker.Item objects loaded into an array using JSX (items.push(<Picker.Item....). It turns out to be very easy to add these to the Picker. Just add items in braces inside the Picker tags, like this:

<Picker>
{items}
</Picker>

As soon as this is done, like magic, the Picker reflects the changes. A dropdown appears with the text Star Wars selected by default.

Now you can click the dropdown, and try to select a different movie, but what you’ll find is that the dropdown is stuck at Star Wars – you can’t select anything else!

For a finishing touch, let’s make it possible for the user to select a different movie. The Picker documentation tells us how to do this by adding the selectedValue attribute and the onValueChange methods like this:

selectedValue={this.state.movie}
onValueChange={(itemValue, itemIndex) =>
    this.setState({ movie: itemValue })
}

After adding this I can select any movie, and that movie stays selected! Here’s my final code:

import React, { Component } from 'react';
import { View, Picker } from 'react-native';

export default class HelloWorldApp extends Component {
    componentDidMount() {
        return fetch('https://facebook.github.io/react-native/movies.json')
            .then((response) => response.json())
            .then((responseJson) => {
                console.log(responseJson);
                this.setState({
                    isLoading: false,
                    dataSource: responseJson.movies,
                }, function () {

                });

            })
            .catch((error) => {
                console.error(error);
            });
    }

    render() {
        if (this.state && !this.state.isLoading) {
            let items = [];
            var length = this.state.dataSource.length;
            for (var i = 0; i < length; i++) {
                var item = this.state.dataSource[i];
                // Really, really important to not put quotes around these braces:
                items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
            }
            return <View>
                <Picker selectedValue={this.state.movie}
                    onValueChange={(itemValue, itemIndex) =>
                        this.setState({ movie: itemValue })
                    }>
                    {items}
                </Picker>
            </View>;
        } else {
            return (<View></View>);
        }
    }
}

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Simple debugging tool in React Native

TL;DR: If you want to debug React Native code really quickly, console.log and console.warn can help.

In my previous post, I described how I ported the React Clock app to React Native. This is the code for my simple app:

import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
import Clock from './Clock';

export default class HelloWorldApp extends Component {
    render() {
        return (
            <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
                <Text style={{ fontWeight: 'bold', padding: 10 }}>Hello, world!</Text>
                {/* padding does not work with Button!! */}
                <Button style={{ fontWeight: 'bold', padding: 40 }} title="Click me" >Click Me!</Button>
                {/* Since padding does not work with Button, we add an empty text area */}
                <Text>{""}</Text>
                <Clock />
            </View>
        );
    }
}

For my next project, I decided to do something more realistic. I wanted to figure out how to fetch data from a REST API.

I already had the Android emulator started (see previous post). A quick look at the React-Native networking documentation told me that doing a fetch should be a piece of cake. Because I didn’t want to copy their entire sample app, but just reuse their fetch call, I copied the componentDidMount method, and pasted it into my application above the render method:

componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
    .then((response) => response.json())
    .then((responseJson) => {

    this.setState({
        isLoading: false,
        dataSource: responseJson.movies,
    }, function(){

    });

    })
    .catch((error) =>{
    console.error(error);
    });
}

(The componentDidMount method may be familiar to you from React.js development.)

I didn’t see any errors when I did this, but I also couldn’t tell whether the fetch method had worked! If I had been building this app using JavaScript in a web browser, I could have quickly checked the results by adding a console.log statement to print out responseJson. I tried this, in fact, but nothing noticeable happened onscreen when I made my change. It took a little while, but I finally noticed that my statements were being logged in the terminal window that was running the Metro server (where I’d run the npm start command)! It took me a while before I noticed this because I’m not usually looking at the terminal unless I’m trying to debug a problem.

A quick search also told me that I could use console.warn to display text on the emulator’s screen. I added console.warn(responseJson); just above the setState call, and I could see that the method had succeeded, and I could also see part of the responseJson content in the YellowBox which appeared. Clicking on this YellowBox warning gave me a fullscreen view of the JSON.

Probably it’s a bad idea to display debug messages using console.warn, but if I were debugging on a device without the help of Metro server, I think console.warn would come in handy.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Invariant violation: Text strings must be rendered within a Text component

TL;DR: To display text in React Native, you must always use a Text tag. This is different from React.js, where text can be displayed in html tags like <div> or <h1>.

For my next mini React Native project, I’m porting the React Clock app to React Native. FYI I’m doing this work on Ubuntu 16.04.

I have to start up my Android emulator first. I list the available ones like this:

emulator -list-avds
Galaxy_Nexus_API_23
Galaxy_Nexus_API_28
Samsung_S4_mIni_API_17

I pick one, and start it:

emulator -avd Galaxy_Nexus_API_28

I didn’t want to have to fire up Android Studio every time I worked on a React Native project, so running the emulator from the command line is super useful. Note the emulator has nothing to do with React Native, per se, and it’s just running in a standalone mode. I can run my emulator commands from any directory; I just open a terminal and do it.

I had already gotten started with React Native. I had a folder called AwesomeProject with a directory structure like this:

...
ios/
android/
App.js

I step into this directory and run the commands npx react-native run-android followed by npm start. I see my project load into the emulator.

I’m using VS Code as my IDE for React Native development. I have no trouble making a small change or two to my App.js file, and I see these changes immediately loaded into the emulator.

Next, I add a file called Clock.js in the same directory as my App.js class.

import React from 'react';
export default class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

This is almost the same as the Clock.js code in the React.js state and lifecycle demo. I’ve removed the ReactDOM.render method because I don’t want the clock rendering immediately. Also, I’ve exported the class so it can be used by other components.

Now I add the Clock to my App. There’s just one line to import it:

import Clock from './Clock';

And a tag to add it:

<Clock/>

This is what my App.js file looks like:

import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
import Clock from './Clock';

export default class HelloWorldApp extends Component {
    render() {
        return (
            <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
            <Text style={{ fontWeight: 'bold', padding: 10 }}>Hello, world!</Text>
            {/* padding does not work with Button!! */}
            <Button style={{ fontWeight: 'bold', padding: 40 }} title="Click me" >Click Me!</Button>
            {/* Since padding does not work with Button, we add an empty text area */}
            <Text>{""}</Text>
            <Clock/>
            </View>
        );
    }
}

As soon as I did this, I saw an error message in my emulator:

The error message reads “Invariant violation: Text strings must be rendered within a component. This error is located at: in h1 (at Clock.js:28) in dev (at Clock.js:27)…”

Since the location of the error is very nicely displayed, I can quickly find the problem. The render method of my React.js Clock class is

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );

and the complaint is about the text “Hello, world!” within the <h1> tags. It didn’t take long before I discovered the problem in the React Native documentation for the Text component: “In React Native, we are more strict about it: you must wrap all the text nodes inside of a component. You cannot have a text node directly under a <View>.”

Let me just try using a Text tag instead of h1 and h2 tags. First I add the import statement:

import { Text } from 'react-native';

And then I swap out <h1> and <h2> for <Text>. That seems to work, but now I have a new error: “Invariant violation: View config not found for name div. Make sure to start component names with a capital letter.”

I already know the complaint is about the div tag in Clock.js. Whoops, divs do not live in native apps. I’ll just change my div tag to a Text tag and see what happens. Here’s my render code:

  render() {
    return (
        <Text>
            <Text>Hello, world!</Text>
            <Text>It is {this.state.date.toLocaleTimeString()}.</Text>
        </Text>
    );
  }

And here’s my running clock!

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Unable to load script. Make sure you’re either running a Metro server…

TL;DR: run npm start in your project root to avoid this error! I’m using Ubuntu 16.04 and Android, YMMV.

In teaching myself React, I’ve been pleasantly surprised by the documentation provided by Facebook. It’s very clear, I’ve been following along easily, and I never hit a speed bump. I was expecting something similar when I started on React Native.

Unfortunately, the React Native docs are a little less polished than those for React.

I started at the appropriately named Getting Started page. I’m running Ubuntu 16.04, and I’ve done Android development, so I followed the “React Native CLI Quickstart” choose-your-own-adventure path, clicking on “Development OS: Linux” and “Target OS: Android”.

I followed the instructions to the letter, except for a few things. I already had Android Studio installed, for example, so I didn’t have to do that. However, I initialized a fresh new React Native project using their installer, just as they said, even using the same project name: npx react-native init AwesomeProject.

I got down to the section entitled “Running your React Native application”, and did as instructed:

cd AwesomeProject
npx react-native run-android

This is what I saw in the Emulator: a message with white letters on a red background saying "Unable to load script. Make sure you're either running a Metro server (run 'react-native start') or that your bundle 'index.android.bundle' is packaged correctly for release."

This was not one of those cases where I immediately knew what was wrong. Why are they talking about “Metro server”? How would I know if my bundle is packaged correctly for release??

I tried doing as the error message suggests:

~/AwesomeProject$ react-native start
react-native: command not found

No.

I went down one rabbit hole after another trying to fix the problem: First, I switched to USB debugging on an Android mobile device, because I thought the most obvious solution would be a problem with the Android Emulator (quite often, that is the problem). I got the same message there. (At this point, I started calling this page the “red screen of death”).

Finally, I got the app working in my mobile device by doing a release build:

~/AwesomeProject$ npx react-native run-android --variant=release

That worked! The app looked like this in my mobile device:

That was confidence inspiring because at least something worked. But it wasn’t useful; I wanted to be able to do hot reloading of my changes, and the install process of the release build was taking two to three minutes. No way was I going to spend 2 minutes waiting to see my changes.

Long story short, I finally figured out what was wrong (thank you, Stack Overflow).

The solution is to run npm start in the root of the project, like this:

~/AwesomeProject$ npm start

NOT react-native start, which was suggested in the error message, as I mentioned above. That was a total fail.

When I ran npm start in the command line, I saw this:

~/AwesomeProject$ npm start

> AwesomeProject@0.0.1 start /home/fullstackdev/AwesomeProject
> react-native start

┌──────────────────────────────────────────────────────────────────────────────┐
│                                                                              │
│  Running Metro Bundler on port 8081.                                         │
│                                                                              │
│  Keep Metro running while developing on any JS projects. Feel free to        │
│  close this tab and run your own Metro instance if you prefer.               │
│                                                                              │
│  https://github.com/facebook/react-native                                    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Looking for JS files in
   /home/fullstackdev/AwesomeProject 

Loading dependency graph, done.

 BUNDLE  [android, dev] ./index.js ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 100.0% (449/449), done.

 LOG  Running "AwesomeProject" with {"rootTag":1}

Notice the important message: “Keep Metro running while developing on any JS projects“. Doh! Thanks for telling me that.. now that it’s started, lol!

But now I’ve got my “Hello World” app running, and I can proceed working on something more interesting.

If you found this interesting, click the subscribe button below! I write a new post about once a week.