I am following the Laracast's API tutorial and trying to create an ApiController that all the other controllers extend. ApiController is responsible for response handling.
class ApiController extends Controller
{
protected $statusCode;
public function getStatusCode()
{
return $this->statusCode;
}
public function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
}
public function respondNotFound($message = 'Not Found!')
{
return Reponse::json([
'error' => [
'message' => $message,
'status_code' => $this->getStatusCode()
]
]);
}
}
And i also have a ReportController that extends ApiController.
class ReportController extends ApiController
{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$report = Report::find($id);
if (! $report ) {
$this->respondNotFound(Report does not exist.');
}
return Response::json([
'data'=> $this->ReportTransformer->transform($report)
], 200);
}
}
When i try to call respondNotFound method from ReportController i get
Class 'App\Http\Controllers\Response' not found error
eventhough i add use Illuminate\Support\Facades\Response;to parent or child class i get the error. How can i fix this ?
Any help would be appreciated.
Since it's a facade, add this:
use Response;
Or use full namespace:
return \Response::json(...);
Or just use helper:
return response()->json(...);
Related
I have a StripeClient service provider which needs a key to instantiate:-
namespace App\Providers;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use Stripe\StripeClient;
class StripeServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(StripeClient::class, function ($app) {
return new StripeClient(config('services.stripe.secret'));
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return [StripeClient::class];
}
Then a trait with a bunch of api call functions like this:-
trait StripeClientTrait
{
protected $stripe;
function __construct(StripeClient $stripeClient)
{
$this->stripe = $stripeClient;
}
/**
* #param User $user
*
* #return \Stripe\Customer
* #throws \Stripe\Exception\ApiErrorException
*/
function createCustomer(User $user)
{
return $this->stripe->customers->create([ 'name' => $user->fullname,
'email' => $user->email
]);
}
...
The trait works in a controller perfectly as expected:-
class SubscriptionContoller extends Controller
{
use StripeClientTrait;
public function checkout()
{
try {
$customer = $this->createCustomer(Auth::user());
if($checkoutSession = $this->createCheckoutSession($customer)) {
return redirect($checkoutSession->url);
}
} catch (ApiErrorException $ex){
Log::error($ex->getMessage());
return back()->with(['error'=>$ex->getMessage()]);
}
return back();
}
...
But I now need to use the trait in a model to provide access to some api functions.
class Company extends Tenant
{
use HasFactory, StripeClientTrait;
but adding the trait causes:-
Too few arguments to function App\Models\Company::__construct(), 0 passed in /home/vagrant/code/profiler/vendor/spatie/laravel-multitenancy/src/Models/Concerns/UsesTenantModel.php on line 13 and exactly 1 expected
Can anyone tell me how to implement the trait without using the constructor? I just need some static function helpers to lookup stuff on the API.
Thanks for any guidance :-)
having persevered I've found this way to use the service container in a model:-
public function getPrices()
{
$stripe = app(StripeClient::class);
return $stripe->prices->all(['active'=>true]);
}
But would still like to understand how to use the trait in the model, if anyone could explain I'd be grateful
This is my PlayerController, Player & Session Model and Resource.
I want to use the input (sessionId from SessionsTable) to fetch user from the room with the same id (userSession) and return an array in this format: [{userId:1, userName: stacki, userVote:8},{...},...]
I already asked [here][1] to achieve this and now im stuck with this error.
What do I have to change in order to solve this issue? Simply adding ->first() does not solve my issue, I need more than one record.
namespace App\Http\Controllers;
use App\Player;
use Illuminate\Http\Request;
use App\Http\Resources\Players as PlayerResource;
class PlayerController extends Controller
{
public function index(Request $request)
{
$room = $request->input('sessionId');
$currentPlayers = Player::where('userSession', $room)->get();
return PlayerResource::collection($currentPlayers);
}
public function create()
{ }
public function update()
{ }
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Player extends Model
{
protected $fillable = [];
public $sortable = [
'userId',
'userName',
'userVote'
];
public function sessions()
{
return $this->hasMany('App\Session');
}
public function players(){
return $this->belongsToMany('App\Session');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Session extends Model
{
protected $fillable = [];
public function user(){
return $this->belongsToMany('App\Player');
}
public function creator()
{
return $this->hasOne('App\Player', 'userId');
}
}
class Players extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'userId' => $this->sessionId,
'userName' => $this->userName,
'userVote' => $this->userVote
];
}
}
`
[1]: https://stackoverflow.com/questions/58062014/display-db-entries-in-json-array-in-controller-laravel-php
Your Player class might extends the Illuminate\Http\Resources\Json\JsonResource instead of ResourceCollection.
This should solve your problem.
use Illuminate\Http\Resources\Json\JsonResource;
class Players extends JsonResource
{
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'userId' => $this->sessionId,
'userName' => $this->userName,
'userVote' => $this->userVote
];
}
}
Hope it helps.
I have custom Request class:
class ApiRequest extends FormRequest
{
...
public function locale()
{
$lang = $this->header('Accept-Language');
return $lang ? $lang : 'uz';
}
}
and API recourse:
class SomeResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
...
];
}
}
but I can't use ApiRequest's method locale() in SomeResource. Because toArray() accepts only \Illuminate\Http\Request.
Is there any idea that I pass my class into this? Or a better solution from you.
The request instance bound in the container is injected into the JSON resource class when the response is created.
One method to achieve what you want would be to create your custom request that extends the standard request class and then bind that in the container as the request instance to be used for the remainder of the request. This could be done in a middleware assigned specifically to the API group or just in specific controllers.
This will then be injected into the toArray() method in your JSON resource class when the response is built and your custom methods will be available to use.
Custom Request Class
class ApiRequest extends Request
{
...
public function locale()
{
$lang = $this->header('Accept-Language');
return $lang ? $lang : 'uz';
}
}
API Middleware
class ApiMiddleware
{
...
public function handle($request, $next)
{
$request = app()->instance('request', ApiRequest::createFrom($request));
return $next($request);
}
}
JSON Resource
class SomeResource extends JsonResource
{
public function toArray($request)
{
// $request is now instanceof ApiRequest
return [
'id' => $this->id,
'locale' => $request->locale()
];
}
}
API Resources should receive model instances not Requests itself. This is an example:
ApiRequest.php
ApiRequest extends Request {
public function authorize() { /** your logic */ }
public function rules() { /** your logic */ }
}
MyCoolController.php
MyCoolController extends Controller {
public function myFunction(ApiRequest $request)
{
$lang = $request->header('Accept-Language') ?? 'uz';
\App::setLocale($lang); // <--
$model = MyModel::find($request->get('id'));
return new SomeResource($model);
}
}
I created a base Resource class, that all my other resource classes extend it with my custom method:
class BaseResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
protected function locale($request)
{
$lang = $request->header('Accept-Language');
return $lang ? $lang : 'uz';
}
}
and I use it in child class:
class SomeResource extends BaseResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
$lang = $this->locale($request);
return [
'id' => $this->id,
'hash' => $this->hash,
'name' => $this->translation('name', $this->locale($request)),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
I am getting the following error in my Laravel app, could someone help me troubleshoot this exception?
FatalErrorException in SerializableClosure.php(153) : eval()'d code
line 2: Call to a member function getOwnerEmail() on array
My getter is in a Notices.php model:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Notice extends Model {
/**
* A notice is created by a user
* #return [type] [description]
*/
public function user()
{
return $this->belongsTo('App\User');
}
/**
* Get the email address of the notice
* #return [type] [description]
*/
public function getOwnerEmail()
{
return $this->user->email;
}
NoticesController.php
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Provider;
use App\Notice;
use Illuminate\Http\Request;
class NoticesController extends Controller {
public function store(Request $request)
{
$notice = $this->createNotice($request);
\Mail::queue('emails.dmca', compact('notice'), function($message) use ($notice) {
$message->from($notice->getOwnerEmail())
->to($notice->getRecipientEmail())
->subject('DMCA Notice');
});
return redirect('notices');
}
public function createNotice(Request $request)
{
$notice = session()->get('dmca') + ['template' => $request->input('template')];
\Auth::user()->notices()->create($notice);
return $notice;
}
public function create()
{
// get list of providers
$providers = Provider::lists('name', 'id');
return view('notices.create', compact('providers'));
}
You may try this:
public function createNotice(Request $request)
{
$notice = session()->get('dmca') + ['template' => $request->input('template')];
return \Auth::user()->notices()->create($notice);
}
Im using ZF2 and I need to render same view (html page) in both add and edit actions. Is there a way to do it in ZF2 ?
In your controller, you can set the view script that will be rendered:
function someAction()
{
$result = new ViewModel();
$result->setTemplate('somemodule/somecontroller/arbitraryscript');
return $result;
}
And if you want to set one template for all Actions just rewrite your construtor methode:
<?php
namespace MyModel\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class IndexController extends AbstractActionController
{
/**
* #var ViewModel
* #access protected
*/
protected $viewModel;
public function __construct()
{
$this->viewModel = new ViewModel();
$this->viewModel->setTemplate('MyModel/index/default.phtml');
}
public function indexAction()
{
$this->viewModel->setVariables(array(
'message' => 'Hello indexAction()'
));
return $this->viewModel;
}
public function otherAction()
{
return $this->viewModel->setVariables(array(
'message' => 'Hello otherAction()'
));
}
}