0

We are moving an older PHP project over to laravel. We are trying to post JSON to our api we created, but are not aware how to have the JSON be bound to a model. We added the model as a parameter to the function, it is created but none of the properties are set on it from the JSON. Does this type of model binding exist in laravel?

class CalculatorModel
{
   /**
    * Value A.
    *
    * @var integer
    */
   public $A;

   /**
    * Value B.
    *
    * @var integer
    */
   public $B;
}

class CalculatorController
{
  // What is trying to be achieved.
  public function add(CalculatorModel $model)
  {
    return Calculator::Add($model);
  }

  // What we are trying to avoid
  // as there is a lot of properties/objects in our real world JSON
  public function add(Request $request)
  {
    $a = $request->json()->all();
    $m = new CalculatorModel();
    $m->A = $a['A'];
    $m->B = $a['B'];
    ....
    return Calculator::Add($m);
  }
}
// in reoutes/api.php
Route::post('add', 'API\CalculatorController@add');

// External library's class
class Calculator
{
    public static function Add(CalculatorModel $m)
    {
        return $m->A + $m->B;
    }
}

Simple JSON post

{
    "A": 2,
    "B": 2
}

In ASP.Net, we are able to add a [FromBody] attribute to the parameter so that ASP.Net would bind the content body as the model instead of form content. We are looking for similar functionality in laravel.

John C
  • 1,761
  • 2
  • 20
  • 30
  • Sounds like model binding is not what you want here, they are for database access. Try `return request()->A + request()->B` or to debug it `dd(request()->json());` or `dd(request()->json()->all());` – PKeidel Sep 06 '20 at 15:18
  • Ok, I may be using the incorrect name for laravel for what we are after. As you can do this with form data posts in laravel. It binds the form variables to the property of the class type in the parameter, we are needing this for JSON posts. They talk about the way to get it to work with form data here. https://stackoverflow.com/questions/37347415/laravel-access-model-instance-in-form-request-when-using-route-model-binding – John C Sep 06 '20 at 15:31
  • Are you looking to take advantage of [Eloquent API Resources](https://laravel.com/docs/7.x/eloquent-resources) ? – FullStackOfPancakes Sep 06 '20 at 23:06
  • @FullStackOfPancakes we are not. – John C Sep 06 '20 at 23:07
  • I figured something out that gets it working quite well. I will write up an answer with a working example within the next day or two. – John C Sep 07 '20 at 00:11

3 Answers3

0

There is no such binding in Laravel. Laravel binding is about Models/DB access as @PKeidel said. All you need is controller method without any models.

public function add(Request $request)
{
    return $request->A + $request->B;
}

UPD: What about new constructor for CalculatorModel class?

public function __construct(array $properties = [])
{ 
    foreach ($properties as $key => $value) {
        $this->{$key} = $value;
    }
}

public function add(Request $request)
{
    $m = new CalculatorModel($request->all());

    return Calculator::Add($m);
}

In any case Laravel does not offer out of the box solution for this.

aleksejjj
  • 1,715
  • 10
  • 21
  • But, that does not work for json, that only works for form data being posted. And we are trying to avoid having to copy all the data from an array into a model that needs to be passed to a library function. I updated the question with a more in depth example of what we are trying to achieve. – John C Sep 06 '20 at 16:01
0

Try this to wrap your API, which can then be used by Eloquent as if it were a database model:

https://github.com/CristalTeam/php-api-wrapper

dietcheese
  • 78
  • 6
-1

All what models are about is saving/reading something from the database. So if this is not what you want, forget about it. Because in Laravel models are bound to database tables ;-)

If you just want so receive some values as json, do a calculation and return a value you are thinking to complicated.

Create a route:

Route::post('add', function() {
  $data = request()->json();
  return $data->get('A') + $data->get('B');
});

Or:

Route::post('add', function(\Illuminate\Http\Request $r) {
  return $r->A + $r->B;
});

This is all it takes.

After that just make sure to send your data with json header. Like so:

fetch('/add', {
    method:"post",
    headers: {'Content-Type': 'application/json'},
    body: '{"A": 2,"B": 2}'
})
.then((d) => d.text())
.then((html) => {
    output.innerHTML = html;
})

See it in action here: https://laravelplayground.com/#/snippets/006b4871-5d92-4a2d-b8af-8a21423024e6

PKeidel
  • 2,559
  • 1
  • 21
  • 29
  • Laravel is a MVC framework... Models are nothing more than an object with properties. They are not by any means bound by a database. Laravel has a ORM to allow easy model binding to/from a database, but that does not enforce a model to be only for database usage. – John C Sep 06 '20 at 22:25
  • Of course it is an object and you can do many things with it. But I thought to a laravel beginner that statement made it clear that you don't have to use a model and can just use the code I provided for you. The proof it is working is the laravelplayground link at the end – PKeidel Sep 07 '20 at 12:04