首页 > 解决方案 > Create an api using lumen and neo4j

问题描述

I want to create an api rest using lumen that it will comunicate with neo4j, for this purpose I'm using NeoEloquent. I've already read the NeoEloquent's documentation but I'm confused. I've understand how lumen it work with a relational database, there is a model, a controller, every action that I want to do on my db pass through a routes that specify the method to use, but I don't understand how this work with a graph database. In particular I don't understand how can I create new label, retrieve all label and relationship using the Http methods. I've try to follow the same procedure that it's explain in this guide (clearly readapting it to my use case) but without success.

Example

Let we say that we have two labels with a many to many relationship, this labels will be Exhibit and Zone. We want to retrieve the zone that is associate to the Exhibit that has a specific identificator. So, the query will be something like this:

MATCH (e:Exhibit)-[belongs_to]->(z:Zone) WHERE e.exhibit_id = {exhibit_id} RETURN z 

For do this query we need to have this routes that it has to present in web.php file:

$router->get('/', function () use ($router) {
    return $router->app->version();
});

$router->group(['prefix' => 'api'], function () use ($router) {

    $router->get('exhibit',  ['uses' => 'ExhibitController@showAllExhibit']);

    $router->get('exhibit/{exhibit_id}', ['uses' => 'ExhibitController@retrieveZone']);
  });

With this routes we are saying: when come a request with a get method, go inside the ExhibitController class and call the retrieveZone function. This is what is present in controller class:

<?php

namespace App\Http\Controllers;

use App\Exhibit;
use Illuminate\Http\Request;

class ExhibitController extends Controller
{

    public function showAllExhibit()
    {
        return response()->json(Exhibit::all());
    }

    public function showOneExhibit($id)
    {
        return response()->json(Exhibit::find($id));
    }

    public function create(Request $request)
    {
        $exhibit = Exhibit::create($request->all());

        return response()->json($exhibit, 201);
    }

    public function update($id, Request $request)
    {
        $exhibit = Exhibit::findOrFail($id);
        $exhibit->update($request->all());

        return response()->json($exhibit, 200);
    }

    public function delete($id)
    {
        Exhibit::findOrFail($id)->delete();
        return response('Deleted Successfully', 200);
    }

    public function retrieveZone($exhibit_id)
    {
        $result = Exhibit::findZone($exhibit_id);
        return response()->json($result,201);
    }
}

When we call retrieveZone function, we will call the function findZone as well that is present in Exhibit model:

<?php

    namespace App;

    use Vinelab\NeoEloquent\Eloquent\Model;
    use Vinelab\NeoEloquent\Facade\Neo4jSchema;

    class Exhibit extends Model{
        protected $label = 'Exhibit';

        protected $fillable = [];

        protected $hidden = [];

        public function belongsToManyZone(){
            return $this->belongsToMany('Zone', 'belongs_to');
        }

        public static function findZone($exhibit_id){
            $exhibit = Exhibit::find($exhibit_id);

            return $exhibit->belongsToManyZone();
        }
    }

The Zone class:

<?php

    namespace App;

    use Vinelab\NeoEloquent\Eloquent\Edges\EdgeIn;
    use Vinelab\NeoEloquent\Eloquent\Model;

    class Zone extends Model{
        protected $label = 'Zone';

        protected $fillable = ['name'];

        protected $hidden = [];
    }

This is what I've done for translate the query using NeoEloquent, Lumen and Fastroute, but the result is 500 Internal Server Error.

Stack Trace

 [2018-10-11 16:37:18] local.ERROR: Symfony\Component\Debug\Exception\FatalThrowableError: Class 'Zone' not found in E:\laravel-projects\api_certose\vendor\vinelab\neoeloquent\src\Eloquent\Model.php:291
Stack trace:
#0 E:\laravel-projects\api_certose\app\Exhibit.php(16): Vinelab\NeoEloquent\Eloquent\Model->belongsToMany('Zone', 'BELONGS_TO')
#1 E:\laravel-projects\api_certose\app\Exhibit.php(22): App\Exhibit->zones()
#2 E:\laravel-projects\api_certose\app\Http\Controllers\ExhibitController.php(44): App\Exhibit::findZone('159')
#3 [internal function]: App\Http\Controllers\ExhibitController->retrieveZone('159')
#4 E:\laravel-projects\api_certose\vendor\illuminate\container\BoundMethod.php(29): call_user_func_array(Array, Array)
#5 E:\laravel-projects\api_certose\vendor\illuminate\container\BoundMethod.php(87): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#6 E:\laravel-projects\api_certose\vendor\illuminate\container\BoundMethod.php(31): Illuminate\Container\BoundMethod::callBoundMethod(Object(Laravel\Lumen\Application), Array, Object(Closure))
#7 E:\laravel-projects\api_certose\vendor\illuminate\container\Container.php(564): Illuminate\Container\BoundMethod::call(Object(Laravel\Lumen\Application), Array, Array, NULL)
#8 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(373): Illuminate\Container\Container->call(Array, Array)
#9 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(339): Laravel\Lumen\Application->callControllerCallable(Array, Array)
#10 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(313): Laravel\Lumen\Application->callLumenController(Object(App\Http\Controllers\ExhibitController), 'retrieveZone', Array)
#11 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(275): Laravel\Lumen\Application->callControllerAction(Array)
#12 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(260): Laravel\Lumen\Application->callActionOnArrayBasedRoute(Array)
#13 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(230): Laravel\Lumen\Application->handleFoundRoute(Array)
#14 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(164): Laravel\Lumen\Application->handleDispatcherResponse(Array)
#15 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(413): Laravel\Lumen\Application->Laravel\Lumen\Concerns\{closure}()
#16 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(166): Laravel\Lumen\Application->sendThroughPipeline(Array, Object(Closure))
#17 E:\laravel-projects\api_certose\vendor\laravel\lumen-framework\src\Concerns\RoutesRequests.php(107): Laravel\Lumen\Application->dispatch(NULL)
#18 E:\laravel-projects\api_certose\public\index.php(28): Laravel\Lumen\Application->run()
#19 {main} {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Class 'Zone' not found at E:\\laravel-projects\\api_certose\\vendor\\vinelab\
eoeloquent\\src\\Eloquent\\Model.php:291)
[stacktrace]
#0 E:\\laravel-projects\\api_certose\\app\\Exhibit.php(16): Vinelab\\NeoEloquent\\Eloquent\\Model->belongsToMany('Zone', 'BELONGS_TO')
#1 E:\\laravel-projects\\api_certose\\app\\Exhibit.php(22): App\\Exhibit->zones()
#2 E:\\laravel-projects\\api_certose\\app\\Http\\Controllers\\ExhibitController.php(44): App\\Exhibit::findZone('159')
#3 [internal function]: App\\Http\\Controllers\\ExhibitController->retrieveZone('159')
#4 E:\\laravel-projects\\api_certose\\vendor\\illuminate\\container\\BoundMethod.php(29): call_user_func_array(Array, Array)
#5 E:\\laravel-projects\\api_certose\\vendor\\illuminate\\container\\BoundMethod.php(87): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#6 E:\\laravel-projects\\api_certose\\vendor\\illuminate\\container\\BoundMethod.php(31): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Laravel\\Lumen\\Application), Array, Object(Closure))
#7 E:\\laravel-projects\\api_certose\\vendor\\illuminate\\container\\Container.php(564): Illuminate\\Container\\BoundMethod::call(Object(Laravel\\Lumen\\Application), Array, Array, NULL)
#8 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(373): Illuminate\\Container\\Container->call(Array, Array)
#9 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(339): Laravel\\Lumen\\Application->callControllerCallable(Array, Array)
#10 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(313): Laravel\\Lumen\\Application->callLumenController(Object(App\\Http\\Controllers\\ExhibitController), 'retrieveZone', Array)
#11 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(275): Laravel\\Lumen\\Application->callControllerAction(Array)
#12 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(260): Laravel\\Lumen\\Application->callActionOnArrayBasedRoute(Array)
#13 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(230): Laravel\\Lumen\\Application->handleFoundRoute(Array)
#14 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(164): Laravel\\Lumen\\Application->handleDispatcherResponse(Array)
#15 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(413): Laravel\\Lumen\\Application->Laravel\\Lumen\\Concerns\\{closure}()
#16 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(166): Laravel\\Lumen\\Application->sendThroughPipeline(Array, Object(Closure))
#17 E:\\laravel-projects\\api_certose\\vendor\\laravel\\lumen-framework\\src\\Concerns\\RoutesRequests.php(107): Laravel\\Lumen\\Application->dispatch(NULL)
#18 E:\\laravel-projects\\api_certose\\public\\index.php(28): Laravel\\Lumen\\Application->run()
#19 {main}
"} 

标签: restneo4jlumenneoeloquentfastroute

解决方案


In order for NeoEloquent to make the connection between your models you also need to define the 'related' model, with the line $this->belongsToMany('Zone', 'belongs_to'); specifies that this class is related to another class (i.e. a node in the graph database) and connected with a relation.

In order to fix your problem you will need to specify this class with at least the following:

<?php

namespace App;

use Vinelab\NeoEloquent\Eloquent\Model;
use Vinelab\NeoEloquent\Facade\Neo4jSchema;

class Zone extends Model{}

Also I would recommend renaming belongsToManyZone() to zones() to improve the readability of the code, because then you can do the following to get all Zones of an Exhibit:

$result = Exhibit::findZone($exhibit_id);
$zones = $result->zones

Otherwise it would have been $result->belongsToManyZone which reads a bit weird.

Also try to change $this->belongsToMany('App\Zone', 'belongs_to'); as this will ensure the right namespace and class will be used and can be found.

I hope this resolves your issue


推荐阅读