Wednesday, April 12, 2017

How to Find a Niche and Validate Early Stage Pricing

I recently wrote an article about my little SaaS experiment in the Russian market that brought me a steady $1,000 in monthly revenue, Menumake.

That article went viral. Many people asked a lot of questions about the details of the building process and what they needed to do to replicate that success.

Here’s a detailed follow-up on the most interesting and complicated parts, plus some tricks on how to find a niche and validate early stage pricing.

Table of contents:

  1. find your niche with 3 simple tactics
  2. bootstrapping a lean MVP
  3. ship quickly with this tech stack
  4. nail early stage pricing with 2 simple tactics

Three Simple Tactics To Find a Niche

How do you find your next idea and validate demand?

After all, you don’t want to waste time building an MVP that nobody wants.

The first and the most obvious way is to have some stats that identify a pain point.

Tactic 1: Data that leads to a pain point

In the SaaS example from my first article, I used Google Analytics data on keywords people used to find my other startup, Postio.

I built Postio to make it easier for people to find and publish content to their social accounts and groups. As a part of its marketing strategy, I bought and published a dozen articles on various subjects targeted at the web services audience to get some extra traffic.

All of a sudden, Postio started to get a large amount of traffic from Google and Yandex (a Russian search engine) with keywords that have nothing to do with Postio itself.

The keyword data looked like this:

Keyword data for Postio

Clearly, people were having real issues with this menu thing.

I had two options:

  1. build it in the existing project
  2. start a spin-off

I chose the latter, because it would be easier to implement SEO strategy and branding later on.

Also, the concept of menu generation is entirely different than the concept of post publishing, which Postio had been built on.

Back to discovering ideas.

Tactic 2: Paving

You can follow the method below, even if you don’t have any existing projects or stats.

I call it paving.

All you have to do is to go to any niche forum and start analyzing what people are doing there and which problems they're trying to solve using the community.

For example, since we’re on SitePoint now, let’s consider their sister site, Flippa.

Most webmaster forums follow a common trend: they all have a marketplace section.

This method of buying and selling online is highly inconvenient and risky.

This path was just asking to be paved. And Flippa has done it, elegantly and efficiently, by creating a spin-off centered around making website and domain transactions seamless.

I also observed this trend in the Russian market, and I’m sure people from other local markets can tell the same story.

DigitalPoint screen shot

Just go to niche communities, listen to people, and every time you see an issue, ask yourself: How can I optimize it using the technology I wield?

It’s incredibly valuable to encourage this attitude as a mental process. I know it’s hard to do, because, since school, we’ve been taught to solve problems, not to find them.

You aren’t always going to be given problems to solve. Reverse engineering the process is a valuable skill to have in the workplace and in your personal projects.

Tactic 3: My niche-specific insight tool

Okay, the third method. It's quite chaotic, but I often use it to reignite my brain and to set it to the right mood. I wrote a simple script that generates a table of entities and corresponding verbs to facilitate discovering new connections.

Here's an example:

A simple script that generates a table of entities and corresponding verbs

Remember, you need to fine-tune this script to match the niche you're trying to get insights into. And it doesn't need to be verbs and entities; you can try anything. The point is to get as many relevant intersections as you can.

Here's the code I used for the example:

<?
$entities = array('image', 'photo', 'text', 'source', 'site', 'traffic', 'money', 'book', 'e-book', 'file', 'smartphone', 'camera', 'notebook', 'cities', 'distances', 'cars', 'mobile', 'book', 'sex', 'love', 'classifieds', 'ads', 'alcohol', 'travel');
$verbs = array('sell', 'buy', 'rent', 'exchange', 'free', 'give', 'book', 'clean', 'find', 'classify', 'compare');

echo '<table style="width: 100%">';

foreach ($entities as $entity)
{
    echo '<tr>';
    foreach ($verbs as $verb)
        echo "<td style='font-size: 14px; padding: 5px; text-align: center'>$verb $entity</td>";
    echo '</tr>';
}

echo '</table>';
?>

There are plenty more tricks for finding a good idea, but let’s not become laser-focused on them now, as we need to move to the next step of bootstrapping a startup.

Continue reading %How to Find a Niche and Validate Early Stage Pricing%


by Alex Moskovski via SitePoint

Java Bean Validation’s validateProperty() and validateValue() in Three Minutes

While it's not widely known, Java Bean Validation ships with the validateProperty() and validateValue() methods, which can be used for validating the individual fields of a constrained class as well as values even before assigning them.

I assume that you already have at least a basic background on how to use the standard for validating objects, but if you want to get a more intimate understanding on how this works, feel free to check my previous article, where I took an in-depth look at Bean Validation's core features.

Selective Validation of Field-Level Constraints

In a typical use case, a constrained domain class like the following will be validated in one single step with a Bean Validation implementation, like Hibernate Validator.

public class User {

    @NotEmpty(message = "Name may not be empty")
    @Size(min = 2, max = 32,
            message = "Name must be between 2 and 32 characters long")
    private String name;

    @NotEmpty(message = "Email may not be empty")
    @Email(message = "Email must be a well-formed email address")
    private String email;

    public User(){}

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // setters and getters for name / email

}

But with validateProperty() and validateValue() the validation process can be performed more selectively.

The validateProperty() Method

Continue reading %Java Bean Validation’s validateProperty() and validateValue() in Three Minutes%


by Alejandro Gervasio via SitePoint

Fetching Data from a Third-Party API with Vue.js and Axios

More often than not, when building your JavaScript application, you would want to fetch data from a remote source or consume an API. I recently looked into some publicly available APIs and found that there is lots of cool stuff that can be done with data from these sources.

With Vue.js, you can literally build an app around one of these services and start serving content to users in minutes.

I will demonstrate how to build a simple news app that will show the top news articles of the day, and will allow users to filter by their category of interest, fetching data from the New York Times API. You can find the complete code for this tutorial here.

Here's what the final app will look like:

Vue.js news web app

To follow along with this tutorial, you will need a very basic knowledge of Vue.js. You can find a great "getting started" guide for that here. I will also be using ES6 Syntax, and you can get a refresher on that here: http://ift.tt/2lsFbvU.

Project Structure

We will keep things very simple by limiting ourselves to just 2 files:

./app.js
./index.html

app.js will contain all the logic for our app, and the index.html file will contain our app's main view.

We'll start off with some basic markup in index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>The greatest news app ever</title>
  </head>
  <body>
    <div class="container" id="app">
      <h3 class="text-center">VueNews</h3> 
    </div>
  </body>
</html>

Then, include Vue.js and app.js at the bottom of index.html, just before the closing </body> tag:

<script src="https://unpkg.com/vue"></script>
<script src="app.js"></script>

Optionally, Foundation can be included, to take advantage of some pre-made styles and make our view look a bit nicer. Include this within the <head> tag:

<link rel="stylesheet" href="http://ift.tt/2nFu3BS">

Creating a Simple Vue App

First, we will create a new Vue instance on the element div#app, and mock the response from the news API using some test data:

// ./app.js
const vm = new Vue({
  el: '#app',
  data: {
    results: [
      {title: "the very first post", abstract: "lorem ipsum some test dimpsum"},
      {title: "and then there was the second", abstract: "lorem ipsum some test dimsum"},
      {title: "third time's a charm", abstract: "lorem ipsum some test dimsum"},
      {title: "four the last time", abstract: "lorem ipsum some test dimsum"}
    ]
  }
});

We tell Vue what element to mount on, via the el option, and specify what data our app would be using via the data option.

To display this mock data in our app view, we can write this markup inside the #app element:

<!-- ./index.html -->
<div class="columns medium-3" v-for="result in results">
  <div class="card">
    <div class="card-divider">
      
    </div>
    <div class="card-section">
      <p>.</p>
    </div>
  </div>
</div>

The v-for directive is used for rendering our list of results. We also use double curly braces to show the contents of each of them.

You can read more on the Vue Template Syntax here

We now have the basic layout working:

Simple news app with mock data

Fetching Data from the API

To make use of the NYTimes API, you'll need to get an API key. So if you don't already have one, head here: http://ift.tt/2dY3ov2, and register to get an API key for the Top Stories API.

Making Ajax Requests and Handling Responses

Axios is a promised-based HTTP client for making Ajax requests, and will work great for our use. It provides a simple and rich API. It is quite similar to the fetch API, but without the need to add a polyfill for older browsers, and some other subtleties.

Previously, vue-resource was commonly used with Vue projects, but it has been retired now.

Including axios:

<!-- ./index.html -->
<script src="http://ift.tt/2hxDEqg"></script>

Now we can make a request to get a list of top stories from the home section, once our Vue app is mounted:

// ./app.js

const vm = new Vue({
  el: '#app',
  data: {
    results: []
  },
  mounted() {
    axios.get("http://ift.tt/2nFHNwg")
    .then(response => {this.results = response.data.results})
  }
});

Remember: replace your_api_key with your actual API key gotten from the NYT Dev Network area.

Now we can see the news feed on our app homepage. Don't worry about the distorted view, we'll get to that in a bit:

News Feed

The response from the NYT API looks like this, via Vue Devtools:

Response from NYT API - Vue.js news app

Tip: Get Vue Devtools to make debugging Vue applications easier.

To make our work a bit neater and reusable, we will do some minor refactoring, and introduce a helper function for building our URLs. We will also register getPosts as a method for our application by adding it to the methods object:

Continue reading %Fetching Data from a Third-Party API with Vue.js and Axios%


by Olayinka Omole via SitePoint

Selector – Micro JavaScript Library Replacement for jQuery

Selector is a micro JavaScript library used as a replacement for jQuery.

The aim of this project is to build a replacement for jQuery while constantly finding optimizations to shrink the overall filesize of the library, keeping the minified, gzip compressed file under 5KB while simultaniously adding more support for jQuery features.


by via jQuery-Plugins.net RSS Feed

Securing Communications on iOS

Mobile security has become a hot topic. For any app that communicates remotely, it is important to consider the security of user information that is sent across a network. In this post, you'll learn the current best practices for securing the communications of your iOS app in Swift. 

Use HTTPS

When developing your app, consider limiting network requests to ones that are essential. For those requests, make sure that they are made over HTTPS and not over HTTP—this will help protect your user's data from "man in the middle attacks", where another computer on the network acts as a relay for your connection, but listens in or changes the data that it passes along. The trend in the last few years is to have all connections made over HTTPS. Fortunately for us, newer versions of Xcode already enforce this.

To create a simple HTTPS request on iOS, all we need to do is append "s" to the "http" section of the URL. As long as the host supports HTTPS and has valid certificates, we will get a secure connection. This works for APIs such as URLSession, NSURLConnection, and CFNetwork, as well as popular third-party libraries such as AFNetworking.

App Transport Security

Over the years, HTTPS has had several attacks against it. Since it's important to have HTTPS configured correctly, Apple has created App Transport Security (ATS for short). ATS ensures that your app's network connections are using industry-standard protocols, so that you don't accidentally send user data insecurely. The good news is that ATS is enabled by default for apps built with current versions of Xcode.

ATS is available as of iOS 9 and OS X El Capitan. Current apps in the store will not suddenly require ATS, but apps built against newer versions of Xcode and its SDKs will have it enabled by default. Some of the best practices enforced by ATS include using TLS version 1.2 or higher, forward secrecy through ECDHE key exchange, AES-128 encryption, and the use of at least SHA-2 certificates.

It's important to note that while ATS is enabled automatically, it doesn't necessarily mean ATS is being enforced in your app. ATS works on the foundation classes such as URLSession and NSURLConnection and stream-based CFNetwork interfaces. ATS is not enforced on lower-level networking interfaces such as raw sockets, CFNetwork sockets, or any third-party libraries that would use these lower-level calls. So if you are using low-level networking, you'll have to be careful to implement ATS's best practices manually.

ATS Exceptions

Since ATS enforces the use of HTTPS and other secure protocols, you might wonder if you will still be able to make network connections that can't support HTTPS, such as when you download images from a CDN cache. Not to worry, you can control ATS settings for specific domains in your project's plist file. In Xcode, find your info.plist file, right click it, and choose Open As > Source Code.

You will find a section called NSAppTransportSecurity. If it is not there, you can add the code yourself; the format is as follows. 

This lets you change ATS settings for all network connections. Some of the common settings are as follows:

  • NSAllowsArbitraryLoads: Disables ATS. Don't use this! Future versions of Xcode will remove this key.
  • NSAllowsArbitraryLoadsForMedia: Allows loading of media without ATS restrictions for the AV Foundation framework. You should only allow insecure loads if your media is already encrypted by another means. (Available on iOS 10 and macOS 10.12.)
  • NSAllowsArbitraryLoadsInWebContent: Can be used to turn off the ATS restrictions from web view objects in your app. Think first before turning this off as it allows users to load arbitrary insecure content within your app. (Available on iOS 10 and macOS 10.12.)
  • NSAllowsLocalNetworking: This can be used to allow local network resources to be loaded without ATS restrictions. (Available on iOS 10 and macOS 10.12.)

The NSExceptionDomains dictionary lets you set settings for specific domains. Here is a description of some of the useful keys you can use for your domain:

  • NSExceptionAllowsInsecureHTTPLoads: Allows the specific domain to use non-HTTPS connections.
  • NSIncludesSubdomains: Specifies if the current rules are passed down to subdomains.
  • NSExceptionMinimumTLSVersion: Used to specify older, less secure TLS versions that are permitted.

Perfect Forward Secrecy

While encrypted traffic is unreadable, it may still get stored. If the private key used to encrypt that traffic is compromised in the future, the key can be used to read all the previously stored traffic. 

To prevent this kind of compromise, Perfect Forward Secrecy (PFS) generates a session key that is unique for each communication session. If the key for a specific session is compromised, it will not compromise data from any other sessions. ATS implements PFS by default, and you can control this feature using the plist key NSExceptionRequiresForwardSecrecy. Turning this off will allow TLS ciphers that don't support perfect forward secrecy.

Certificate Transparency

Certificate Transparency is an upcoming standard designed to be able to check or audit the certificates presented during the setup of an HTTPS connection. 

When your host sets up an HTTPS certificate, it is issued by what is called a Certificate Authority (CA). Certificate Transparency aims at having close to real-time monitoring to find out if a certificate was issued maliciously or has been issued by a compromised certificate authority. 

When a certificate is issued, the certificate authority must submit the certificate to a number of append-only certificate logs, which can later be cross-checked by the client and scrutinized by the owner of the domain. The certificate must exist in at least two logs in order for the certificate to be valid.

The plist key for this feature is NSRequiresCertificateTransparency. Turning this on will enforce Certificate Transparency. This is available on iOS 10 and macOS 10.12 and later.

Certificate and Public Key Pinning

When you purchase a certificate to use HTTPS on your server, that certificate is said to be legitimate because it is signed with a certificate from an intermediate certificate authority. That certificate used by the intermediate authority might in turn be signed by another intermediate authority, and so on, as long as the last certificate is signed by a root certificate authority that is trusted. 

When an HTTPS connection is established, these certificates are presented to the client. This chain of trust is evaluated to make sure the certificates are correctly signed by a certificate authority that is already trusted by iOS. (There are ways to bypass this check and to accept your own self-signed certificate for testing, but don't do this in a production environment.) 

If any of the certificates in the chain of trust are not valid, then the entire certificate is said to be invalid and your data will not be sent out over the untrusted connection. While this is a good system, it's not foolproof. Various weaknesses exist that can make iOS trust an attacker's certificate instead of a legitimately signed certificate. 

For example, interception proxies may possess an intermediate certificate that is trusted. A reverse engineer can manually instruct iOS to accept their own certificate. Additionally, a corporation's policy may have provisioned the device to accept their own certificate. All of this leads to the ability to perform a “man in the middle” attack on your traffic, allowing it to be read. But certificate pinning will prevent connections from being established for all of these scenarios.

Certificate pinning comes to the rescue by checking the server's certificate against a copy of the expected certificate.

In order to implement pinning, the following delegate must be implemented. For URLSession, use the following:

Or for NSURLConnection, you can use:

Both methods allow you to obtain a SecTrust object from challenge.protectionSpace.serverTrust. Because we are overriding the authentication delegates, we must now explicitly call the function which performs the standard certificate chain checks that we've just discussed. Do this by calling the SecTrustEvaluate function. Then we can compare the server's certificate with an expected one.

Here is an example implementation.

To use this code, set the delegate of the URLSession when creating your connection.

Make sure to include the certificate in your app bundle. If your certificate is a .pem file, you will need to convert it to a .cer file in the macOS terminal:

openssl x509 -inform PEM -in mycert.pem -outform DER -out certificate.cer

Now, if the certificate is changed by an attacker, your app will detect it and refuse to make the connection.

Note that some third-party libraries such as AFNetworking support pinning already.

Sanitization and Validation

With all of the protections so far, your connections should be pretty secure against man in the middle attacks. Even so, one important rule regarding network communications is never to blindly trust the data you are receiving. In fact, it's good programming practice to design by contract. Theinputs and outputs of your methods have a contract that defines specific interface expectations; if the interface says it will return an NSNumber, then it should do so. If your server is expecting a string of 24 characters or fewer, make sure that the interface will only return up to 24 characters. 

This helps prevent innocent errors, but more importantly, it can also reduce the likelihood of various injection and memory corruption attacks. Common parsers such as the JSONSerialization class will convert text into Swift data types where these kinds of test can be done.

Other parsers may work with Objective-C equivalent objects. Here is a way to validate that an object is of the expected type in Swift.

Before you send a delegate a method, make sure the object is of the right type so that it will respond to the method—otherwise the app will crash with an “unrecognized selector” error.

Additionally, you can see if an object conforms to a protocol before trying to send messages to it:

Or you can check that it matches a Core Foundation object type.

It's a good idea to carefully choose which information from the server the user can see. For example, it's a bad idea to display an error alert that directly passes a message from the server. Error messages could disclose debugging and security-related information. One solution is to have the server send specific error codes that cause the client to show predefined messages.

Also, make sure you encode your URLs so that they only contain valid characters. NSString’s stringByAddingPercentEscapesUsingEncoding will work. It does not encode some characters such as ampersands and plus signs, but the CFURLCreateStringByAddingPercentEscapes function allows customization of what will be encoded.

Sanitizing User Data

When sending data to a server, be extremely careful when any user input is passed into commands that will be executed by an SQL server or a server that will run code. While securing a server against such attacks is beyond the scope of this article, as mobile developers we can do our part by removing characters for the language that the server is using so that the input is not susceptible to command injection attacks. Examples might be stripping quotes, semicolons, and slashes when they are not needed for the specific user input.

It is good practice to limit the length of user input. We can limit the number of characters typed in a text field by setting the UITextField's delegate and then implementing its shouldChangeCharactersInRange delegate method.

For a UITextView, the delegate method to implement this is:

User input can be further validated so that the input is of an expected format. For example, if a user is to enter an email address, we can check for a valid address:

If a user is uploading an image to the server, we can check that it is a valid image. For example, for a JPEG file, the first two bytes and last two bytes are always FF D8 and FF D9.

The list goes on, but only you as the developer will know what the expected input and output should be, given the design requirements.

URLCache

The data you send over the network has the potential to be cached in memory and on device storage. You can go to great lengths to protect your network communications, as we have been doing, only to find out that the communication is being stored. 

Various versions of iOS have had some unexpected behaviour when it comes to the cache settings, and some of the rules for what gets cached in iOS keep changing over the versions. While caching helps network performance by reducing the number of requests, turning it off for any data you think is highly sensitive can be a good idea. You can remove the shared cache at any time (such as on app startup) by calling:

To disable caching on a global level, use:

And if you are using URLSession, you can disable cache for the session like this:

If you are using an NSURLConnection object with a delegate, you can disable the cache per connection with this delegate method:

And to create a URL request that will not check the cache, use:

Various versions of iOS 8 had some bugs where some of these methods on their own would do nothing. That means it's a good idea to implementing all of the above code for sensitive connections, when you need to reliably prevent caching of network requests.

The Future

It is important to understand the limits of HTTPS for protecting network communications. 

In most cases, HTTPS stops at the server. For example, my connection to a corporation's server may be over HTTPS, but once that traffic hits the server, it is unencrypted. This means that the corporation will be able to see the information that was sent (in most cases it needs to), and it also means that company could then proxy or pass that information out again unencrypted. 

I can't finish this article without covering one more concept that is a recent trend—what is called "end-to-end encryption". A good example is an encrypted chat app where two mobile devices are communicating with each other through a server. The two devices create public and private keys—they exchange public keys, while their private keys never leave the device. The data is still sent over HTTPS through the server, but it is first encrypted by the other party's public key in such a way that only the devices holding the private keys can decrypt each other's messages. 

As an analogy to help you understand end-to-end encryption, imagine that I want someone to send me a message securely that only I can read. So I provide them a box with an open padlock on it (the public key) while I keep the padlock key (private key). The user writes a message, puts it in the box, locks the padlock, and sends it back to me. Only I can read what the message is because I am the only one with the key to unlock the padlock. 

With end-to-end encryption, the server provides a service for communication, but it can not read the content of the communication—they ship the locked box, but they don't have the key to open it. While the implementation details are beyond the scope of this article, it's a powerful concept if you want to allow secure communication between users of your app. 

If you want to learn more about this approach, a place to start is the GitHub repo for Open Whisper System, an open-source project.

Conclusion

Almost all mobile apps today will communicate across a network, and security is a critically important but often neglected aspect of mobile app development. 

In this article, we've covered some security best practices, including simple HTTPS, application hardening of network communications, data sanitization, and end-to-end encryption. These best practices should serve as a foundation for security when coding your mobile app.

And while you're here, check out some of our other popular iOS app tutorials and courses!

  • iOS 10
    Using the Speech Recognition API in iOS 10
    Patrick Balestra
  • iOS SDK
    How to Use Apple's CloudKit for Push Notifications
    Davis Allie
  • Mobile Development
    Back-End as a Service for Mobile Apps
    Bala Durage Sandamal Siripathi
  • iOS
    Go Further With Swift: Animation, Networking, and Custom Controls
    Markus Mühlberger

by Collin Stuart via Envato Tuts+ Code

Authentication and Sharing in Android with the Google+ API

In this tutorial I will show how to connect your Android application to the Google Plus API and use it for login, getting and sharing data.

Find the completed project on GitHub.

Create Android Project

Open Android Studio and create a New Project, naming it as you wish. Click Next, choose Minimum API level 18 and click Next again. Choose Blank Activity as the first activity, name it LoginActivity and click Finish.

Continue reading %Authentication and Sharing in Android with the Google+ API%


by Theodhor Pandeli via SitePoint

Real-Time Laravel Notifications and Follows? Sure, with Stream!

With Laravel, it's pretty easy to create newsfeed sites, blogs, or even forums where people post content, comment, or even mark some of these posts as favorite. To spice things up, we can make the app more lively by adding notifications for actions performed by other users. In this tutorial, we'll be relying on a service called Stream to add this functionality to our app.

Stream is an API for Building Feeds, Activity Streams, and Notification Systems

Stream.io logo with Laravel colors

The API can be used with many languages and frameworks. Visit the website and click on Try the API. Select PHP as the language of choice since we'll be working with PHP. The tutorial should give you a good overview of the type of notifications we can get with Stream. There's an official package for Laravel, which makes it even easier to integrate this service into any Laravel app.

For this tutorial, we are going to use an existing project to try out the Stream API. Just clone this repo. It's a simple Laravel 5.4 blog where users get to perform CRUD operations on blog posts. We'll add the ability to follow other users shortly. We will then create feed sections with different types of notifications telling us who did what and when. Our main focus in this tutorial will be on people creating new blog posts and following each other. The complete code for this tutorial can be found here.

Project Setup

It's recommended you use Homestead Improved for quickly getting up and running with a professional development environment that contains everything you might need.

git clone http://ift.tt/2ozoAvM

With the repo set up locally, we should then prepare a database before running any migrations. We will use MySQL for this tutorial. After setting up the database, run:

cp .env.example .env

I have the database connection section in my .env file looking like this:

DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

Since this is not a fresh Laravel install, we will have to run composer install to install various packages and dependencies for this project:

composer install

Then run:

php artisan migrate
php artisan db:seed

The app has some seed data to generate 10 posts. If we serve our app and visit /posts, we should be greeted with ten posts.

All set! We can now sign up new users and even create blog posts. The link to create a new post is in the navbar. Let's add the ability to follow other users. By following another user, we'll be updated on their activities i.e. creating new posts or following other users.

Following Users

For this, we'll start by generating a Follow model alongside a migration. Note. however, that for large scale projects, it's recommended to create followers and following tables to make querying relations easier:

php artisan make:model Follow -m

Let's update the up method of the newly generated migration to this:

public function up()
{
    Schema::create('follows', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id')->index();
        $table->integer('target_id')->index(); // ID of person being followed
        $table->timestamps();
    });
}

Here, we are adding a user_id column because a follow belongs to a user. Let's now run the migrate command to create the follows table:

php artisan migrate

We are yet to define the relationship between follows and users. Open the User model file and add the relationship:

app/User.php

[...]
class User extends Authenticatable
{
    [...]
    public function follows() {
        return $this->hasMany(Follow::class);
    }
}

Inside app/Follow.php, let's add the target_id to the list of mass assignable attributes. We are also going to define the relationship specifying that a follow belongs to a user:

app/Follow.php

[...]
class Follow extends Model
{
    protected $fillable = ['target_id'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
[...]

With the relationships defined, we can now add the ability to follow other users. Let's define the routes for the follow and unfollow actions.

Continue reading %Real-Time Laravel Notifications and Follows? Sure, with Stream!%


by Christopher Vundi via SitePoint