<repo_name>nathanhollows/flatsAPI<file_sep>/README.md
# flatsAPI
An API for storing and retrieving flats

The API is currently being tested on [nathanhollows.com/flats/](https://nathanhollows.com/flats/)

| Method | Url | Action |
|:------ |:--- |:------ |
| `GET`  | /api/flats | Retrives all current flats, sorted by date added |
| `POST` | /api/flats | Save a new listing. Returns the ID | 
| `GET`  | /api/flats/id/{id} | Retrieve a flat by ID |
| `DELETE` | /api/flats/id/{id} | Remove a flat from the listings |

Content type must be `application/x-www-form-urlencoded` (for now)

## Fields

| Value | Type | Default | Description |
|:----- |:---- |:------- | :---------- |
| id | string | UUID | An automatically generated UUID |
| price * | int | NULL | The cost per week |
| bedrooms * | int | NULL | |
| bedrooms * | int | NULL | |
| parking * | int | NULL | The number of off street parks |
| heroText * | string | NULL | Short description of listing. 100 char limit |
| description * | string | NULL | Description of listing |
| agent * | string | NULL | |
| image * | string | NULL | Image URL |
| url * | string | NULL | URL for listing |
| type * | string | NULL | To be decided |
| dateAdded | timestamp | NOW() | Derived when the listing was first added |
| dateAvailable | date | NOW() | When the listing is available |
| dateRemoved | timestamp | NULL | Derived when the listing was removed |
| pets * | int | 0 | `0`: False, `1`: True |
| address * | int | null | A string repesentation of the address |

**Note:** * Accepted in POST `/api/flats/`
<file_sep>/models/Flats.php
<?php

namespace App\Models;

use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Message;
use Phalcon\Validation;

class Flats extends Model 
{
    // UUID
    public $id;
    public $price;
    public $bedrooms;
    public $bathrooms;
    public $parking;
    public $heroText;
    public $description;
    public $agent;
    public $image;
    public $url;
    public $type;
    public $dateAdded;
    public $dateAvailable;
    public $dateRemoved;
    public $pets;
    public $address;
    public $latitude;
    public $longtitude;
}

?>
<file_sep>/index.php
<?php

error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);

use Phalcon\Db\Adapter\Pdo\Mysql as PdoMysql;
use Phalcon\Di\FactoryDefault;
use Phalcon\Http\Response;
use Phalcon\Loader;
use Phalcon\Mvc\Micro;
use Phalcon\Security\Random;

$loader = new Loader();

$loader->registerNamespaces( 
    [
        'App\Models' => __DIR__ . '/models/',
    ]
);

$loader->register();

$di = new FactoryDefault();

$di->set(
    'db',
    function() {
        return new PdoMysql([
            'host'      => 'localhost',
            'username'  => 'user',
            'password'  => '<PASSWORD>',
            'dbname'    => 'flats',
        ]);
    }
);

$app = new Micro($di);

$app->get(
    '/',
    function() {
        echo "https://github.com/nathanhollows/flatsAPI";
    }
);

// I am not proud of this.
// TODO: Move to paginator
// TODO: Move to query builder
$app->get(
    '/api/flats',
    function() use ($app) {
        $listings = $app->modelsManager->createBuilder();

        $limit = $app->request->get("limit", "int", 10000);
        $offset = $app->request->get("offset", "int", 0);

        $filter = "";

        $search = $app->request->getQuery("search", "string", "");
        if ($search != "") {
            $filter = "AND (address LIKE '%$search%'
            OR heroText LIKE '%$search%'
            OR description LIKE '%$search%')";
        }

        if ($app->request->hasQuery("priceLow")) {
            $filter = $filter . " AND price >= " . $app->request->getQuery('priceLow', 'absint', 0);
        }

        if ($app->request->hasQuery("priceHigh")) {
            $filter = $filter . " AND price <= " . $app->request->getQuery('priceHigh', 'absint', 0);
        }

        if ($app->request->hasQuery("bedsLow")) {
            $filter = $filter . " AND bedrooms >= " . $app->request->getQuery('bedsLow', 'absint', 0);
        }

        if ($app->request->hasQuery("bedsHigh")) {
            $filter = $filter . " AND bedrooms <= " . $app->request->getQuery('bedsLow', 'absint', 0);
        }

        $phql = "SELECT id, price, bedrooms, bathrooms, parking,
                    heroText, description, agent, image, url, type,
                    dateAdded, dateAvailable, pets, address
            FROM App\Models\Flats 
            WHERE dateRemoved IS NULL "
            . $filter .
            " ORDER BY dateAdded";

        $flats = $app->modelsManager->executeQuery($phql);

        $response = new Response();
        $response->setJsonContent([
            'status' => 'OK',
            'data'  => $flats,
        ]);
        return $response;
    }
);

$app->post(
    '/api/flats',
    function() use ($app) {
        $request = $app->request;

        $phql = 'INSERT INTO App\Models\Flats
            (id, price, bedrooms, bathrooms, parking, heroText, 
            description, agent, image, type, dateAvailable, 
            pets, address, url) VALUES
            (:id:, :price:, :bedrooms:, :bathrooms:, :parking:, :heroText:, 
            :description:, :agent:, :image:, :type:, :dateAvailable:, 
            :pets:, :address:, :url:)';

        $random = new Random();
        $uuid = $random->uuid();

        $status = $app->modelsManager->executeQuery(
            $phql,
            [
                'id'=> $uuid,
                'address' => $request->getPost("address", "string", null),
                'price' => $request->getPost("price", "absint", null),
                'bedrooms' => $request->getPost("bedrooms", "absint", null),
                'bathrooms' => $request->getPost("bathrooms", "absint", null),
                'parking' => $request->getPost("parking", "absint", null),
                'heroText' => $request->getPost("heroText", "string", null),
                'description' => $request->getPost("description", "string", null),
                'agent' => $request->getPost("agent", "string", null),
                'image' => $request->getPost("image", "string", null),
                'url' => $request->getPost("url", "string", null),
                'type' => $request->getPost("type", "string", null),
                'dateAvailable' => $request->getPost("dateAvailble", null, date("Y-m-d")),
                'pets' => $request->getPost("pets", "absint", null),
            ]
        );

        $response = new Response();

        if ($status->success()) {
            $response->setStatusCode(201, 'Created');
            $response->setJsonContent([
                'status'    => 'OK',
                'data'      => $uuid,
            ]);
        } else {
            $response->setStatusCode(409, 'Conflict');

            $errors = [];

            foreach ($status->getMessages() as $message) {
                $errors[] = $message->getMessage();
            }

            $response->setJsonContent([
                'status'    => 'ERROR',
                'messages'  => $errors,
            ]);
        }

        return $response;
    }
);

$app->get(
    '/api/flats/id/{id}',
    function($id) use ($app) {
        $phql = 'SELECT * FROM App\Models\Flats 
            WHERE id = :id:';

        $flats = $app->modelsManager->executeQuery(
            $phql,
            ['id' => $id]
        );

        echo json_encode($flats);
    }
);

$app->delete(
    '/api/flats/id/{id}',
    function($id) use ($app) {
        $phql = 'UPDATE App\Models\Flats
            SET dateRemoved = CURRENT_TIMESTAMP()
            WHERE id = :id:';

        $status = $app->modelsManager->executeQuery(
            $phql,
            ['id' => $id]
        );

        $response = new Response();

        if ($status->success() === true) {
            $response->setJsonContent([
                'status'    => "OK",
            ]);
        } else {
            $response->setStatusCode(409, 'Conflict');

            $errors = [];

            foreach ($status->getMessages() as $message) {
                $errors[] = $message->getMessage();
            }

            $response->setJsonContent([
                'status'    => 'ERROR',
                'messages'  => $errors,
            ]);
        }

        return $response;
    }
);

$app->handle();
