We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Micro API, Models or not models (1.3.0)

Hi.

I am building a small restful API with 2 gets and 1 put. I am following the guide there is for a restful API with Phalcon and i don't get it all.

In the guide does it create a model, without using the functions in it and then it is needed to do SQL calls.

So what is best to do it? do all the code in the bootstrap/index file or move SQL calls to a model?

Here is my bootstrap/index file index.php

<?php
$loader = new \Phalcon\Loader();

$loader->registerDirs(array(
    __DIR__ . '/models/'
))->register();

$di = new \Phalcon\DI\FactoryDefault();
$app = new \Phalcon\Mvc\Micro($di);

$di->set('db', function() {
    return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
        "host" => "localhost",
        "username" => "patteguf",
        "password" => "xxxxxxxxxxxx",
        "dbname" => "pattegufv3"
    ));
});

$app->get('/pictures', function() use ($app)
{
    $limit = $app['request']->getQuery('limit', 'int', 10);
    $offset = $app['request']->getQuery('offset', 'int', 0);

    if($limit > 50) {
        $response = new Phalcon\Http\Response();
        $response->setStatusCode(403, 'Forbidden');
    }

    $phql = "SELECT p.id, p.filename, p.likes FROM pictures p WHERE p.status = 'Active' ORDER BY p.id DESC LIMIT :limit:,:offset:";

    $pictures = $app->modelsManager->executeQuery(
        $phql,
        array(
            'limit' => $limit,
            'offset' => $offset
        ),
        array(
            'limit' => \Phalcon\Db\Column::BIND_PARAM_INT,
            'offset' => \Phalcon\Db\Column::BIND_PARAM_INT
        )
    );

    $data = array();
    foreach ($pictures as $picture) {
        $data[] = array(
            'id' => $picture->id,
            'filename' => $picture->filename,
            'likes' => $picture->likes
        );
    }

    echo json_encode($data);
});

$app->get('/pictures/{id:[0-9]+}', function($id) use ($app)
{
    $phql = "SELECT p.id, p.filename, p.likes FROM pictures p WHERE p.status = 'Active' AND p.id = :id:";
    $picture = $app->modelsManager->executeQuery($phql,
        array(
        'id' => $id
        ),
        array('id' => \Phalcon\Db\Column::BIND_PARAM_INT))->getFirst();

    $response = new Phalcon\Http\Response();

    if($picture == false) {
        $response->setStatusCode(404, 'Not found');
    } else {
        $response->setJsonContent(array(
            'id' => $picture->id,
            'filename' => $picture->filename,
            'likes' => $picture->likes
        ));
    }

    return $response;
});

$app->put('/pictures/{id:[0-9]+}', function($id) use ($app)
{
    $query = "SELECT p.likes FROM pictures p WHERE p.status = 'Active' AND p.id = :id:";
    $like = $app->modelsManager->executeQuery($query,
    array(
        'id' => $id
    ),
    array('id' => \Phalcon\Db\Column::BIND_PARAM_INT))->getFirst();
    $amountLikes = $like->likes + 1;
    $phql = "UPDATE pictures SET pictures.likes = pictures.likes + 1 WHERE pictures.id = :id:";
    #$phql = "UPDATE pictures p SET `p.likes` = " . $amountLikes ." WHERE `p.id` = :id:";

    $customHash = $app['security']->hash('*patte.!guf#');
    $ipAddress = $app['request']->getClientAddress();
    $userAgent = $app['request']->getUserAgent();
    $response = new Phalcon\Http\Response();

    $app->modelsManager->executeQuery($phql,
        array(
            'id' => $id
        ),
        array(
            'id' => \Phalcon\Db\Column::BIND_PARAM_INT
        ));
        #$app['cookies']->set($customHash, $app['security']->hash("*patte." . $ipAddress . $userAgent . time() . "!guf#"),time() + 30 * 86400); // sets cookie for 1 month
    /*
    } else {
        $response->setStatusCode(403, 'Forbidden');
    }
    */
    return $response;
});

$app->notFound(function () use ($app) {
    $app->response->setStatusCode(404, "Not Found")->sendHeaders();
    echo 'This is crazy, but this page was not found!';
});

$app->handle();

And this is my model i am creating. /models/Pictures.php

<?php
use Phalcon\Mvc\Model,
    Phalcon\Mvc\Model\Query,
    Phalcon\Db,
    Phalcon\Http\Response;

class Pictures extends Model
{
    public function select($id = null, $limit = 10, $offset = 0)
    {
        if(is_null($id))
        {
            if($limit > 50) {
                $response = new Phalcon\Http\Response();
                $response->setStatusCode(403, 'Forbidden');
            }

            $phql = "SELECT p.id, p.filename, p.likes FROM pictures p WHERE p.status = 'Active' ORDER BY p.id DESC LIMIT :limit:,:offset:";

            $pictures = $this->getModelsManager()->executeQuery(
                $phql,
                array(
                    'limit' => $limit,
                    'offset' => $offset
                ),
                array(
                    'limit' => Db\Column::BIND_PARAM_INT,
                    'offset' => Db\Column::BIND_PARAM_INT
                )
            );

            $data = array();
            foreach ($pictures as $picture) {
                $data[] = array(
                    'id' => $picture->id,
                    'filename' => $picture->filename,
                    'likes' => $picture->likes
                );
            }

            return json_encode($data);
        }

        if(!is_null($id))
        {
            $phql = "SELECT p.id, p.filename, p.likes FROM pictures p WHERE p.status = 'Active' AND p.id = :id:";
            $picture = $this->getModelsManager()->executeQuery($phql,
                array(
                    'id' => $id
                ),
                array('id' => Db\Column::BIND_PARAM_INT))->getFirst();

            $response = new Response();

            if($picture == false) {
                $response->setStatusCode(404, 'Not found');
            } else {
                $response->setJsonContent(array(
                    'id' => $picture->id,
                    'filename' => $picture->filename,
                    'likes' => $picture->likes
                ));
            }

            return $response;
        }
    }
}

I haven't figured out how to use it completely. FYI, i do have some errors in the code above i am working on.

I need suggestions how to do this the best/smatest way and easy scalable

Hi, i havent used phalcons micro app, but in terms of best practices, your data manipulation should be in models, so i guess thats the way to go ... then again, if you have in terms of scalability, if your app is intended to grow, im not sure that using micro app might be best approach? perhaps using sinle module application would give you a more robust starting point and structure for your application