This is more of a concept question, so I apologize if it isn't specific enough.
I am coming from a Jquery/AngularJS background; usually I am doing front-end stuff and only work with a back-end sparingly.
I am trying to learn Laravel 5 to expand my skills, but am having trouble conceptually fitting together what I know from Angular with what Laravel is telling me.
I want CRUD functionality to a database using Angular, but I want Laravel to help me get that database from MySQL to JSON so it can be passed.
What I have done is made the following in Laravel:
~Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Pun extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
public $timestamps = false;
}
~Controller:
namespace App\Http\Controllers;
use App\Pun;
use App\Http\Controllers\Controller;
class PunController extends Controller
{
/**
* Show a list of all available puns.
*
* #return Response
*/
public function index()
{
$puns = Pun::all();
return Response::json($puns->toArray());
}
}
}
~Route:
Route::get('showpunsfromdatabase', function () {
return view('???');
});
The question marks above is where I am having trouble. If I understand it correctly, the controller is supposed to query the database as defined in the model, and output the results as JSON. How do I then direct Angular to this controller so I can get this JSON using the $http service? Does it have to go in a view that then pulls it in? I don't really want it in a "view", I just want the data (JSON) available to Angular. Am I thinking about this correctly?
My angular controller looks like this:
$scope.punGenerate = function(){
$http.get("???").then(function (response) {$scope.thePunJSON = response.data;});
}
IF you do this:
Route::get('showpunsfromdatabase', function () {
return view('???');
});
You are not calling the controller, you are returning the view directly. To call the controller your route should look like this:
Route::get('showpunsfromdatabase' , [
'as' => 'showpunsfromdatabase.index',
'uses' => 'PunController#index'
]);
Now, from the controller you should load the view including the info returned by the model:
<?php
namespace App\Http\Controllers;
use App\Pun;
use App\Http\Controllers\Controller;
class PunController extends Controller
{
/**
* Show a list of all available puns.
*
* #return Response
*/
public function index()
{
$puns = Pun::all();
return view('???')
->with(['puns' => json_encode($puns)]);
}
}
It's just an example, because I don't know what are you looking for exactly.
Related
A question has arisen.
Suppose I have an api route that is
get: api/v1/conferences/{conference_id}/languages
The purpose would be to get the languages linked to this conference.
My program, almost always starts with conferences/{conference_id} so the conference_id must always be real. In case the conference_id does not exist, I should throw an exception.
I want to do this without putting any logic in the controllers or any class that has any particular logic of mine. I would like it to be validated by default from the laravel kernel, is that possible?
I mean, i want that every time somebody access to a route which starts with conferences/{conference_id} the program would be able to check if this id is real
Thanks
Use exists in validation rules like:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ConferencesRequest extends FormRequest
{
/**
* #inheritDoc
*/
public function all($keys = null)
{
$data = parent::all();
$data['conference_id'] = $this->route('conference_id');
return $data;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'conference_id' => ['required', 'integer', 'exists:' . App\Models\Conference::class . ',id'],
];
}
}
Or, if you dont want to use a FormRequest class, use this:
p.s. param should be changed to conference instead of conference_id:
use App\Models\Conference;
Route::get('conferences/{conference}/languages', function (Conference $conference) {
//...
});
See: https://laravel.com/docs/9.x/routing#route-model-binding
I've created a Laravel project on Laravel 9.20.0 and I'm attempting to use an API wrapper for Linnworks I found on Github (https://github.com/booni3/linnworks-laravel) within my project. I'm okay with raw PHP but admittedly a complete beginner when it comes to Laravel and object oriented PHP.
In my /routes/web.php file I have:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TestController;
Route::get('test', [TestController::class, 'test']);
In /app/Http/Controllers/TestController.php I have:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\OrderService;
class TestController extends Controller
{
protected $orderService;
/**
* Instantiate a new controller instance.
*
* #return void
*/
public function __construct(OrderService $orderService)
{
$this->orderService = $orderService;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function test()
{
$this->orderService->calculateProfit();
}
}
In /app/Services/OrderService.php I have:
<?php
namespace App\Services;
use Linnworks;
class OrderService {
public function __construct()
{
}
public function calculateProfit()
{
$this->getOrder();
return;
}
public function getOrder()
{
$order = Linnworks::Orders()->GetOrdersByNumOrderId(777678);
echo "<pre>";
print_r($order);
echo "</pre>";
return;
}
}
At this point, I'm just trying to figure out the correct way to use the Linnworks API Wrapper from GitHub within my service class and get it to return something from the Linnworks platform.
I have input the correct API details in the .env file but I'm clearly doing something wrong or missing something obvious (likely due to my lack of experience with object oriented PHP and Laravel) and I'm getting the following error when I load my url /test/:
Booni3\Linnworks\Linnworks::__construct(): Argument #1 ($config) must be of type array, string given, called in /home/username/laravel-projects/project-name/vendor/booni3/linnworks-laravel/src/LinnworksServiceProvider.php on line 49
According to the GitHub readme, usage is as simple as:
$orders = Linnworks::Orders()->getOpenOrders(
25,
1,
null,
null,
'e41b4701-0885-430d-9623-d840d9d46dd6',
null);
Any help or pointers in the right direction will be hugely appreciated as I've hit a bit of a wall.
Thanks in advance
I'm developing an application where my data comes from external server in JSON format.
I would like to set a relationships between each models, but without using a database table.
Is it possible ?
Something like that:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'https://.../server/flights.json';
}
You could make a service class which handles the request and returns class instances:
namespace App\Services;
class FlightService
{
/**
* #var FlightFactory
*/
private $flightFactory;
public function __construct(FlightFactory $flightFactory)
{
$this->flightFactory = $flightFactory;
}
public function getAllFlights()
{
$flightsJson = $this->getFromExternalCurl();
return $this->flightFactory->buildFlightList($flightsJson);
}
private function getFromExternalCurl()
{
return Curl::to('http://www.foo.com/flights.json')
->withData( array( 'foz' => 'baz' ) )
->asJson()
->get();
}
}
Basically the service would make the external API call and the response is passed to a factory which creates the instances.
Note that you just need to add the factory in the construct and it's binded because laravel uses https://laravel.com/docs/5.4/container
namespace App\Factories;
class FlightFactory
{
public function buildFlightList($flightJsonList)
{
$flightCollection = collect();
foreach($flightJsonList as $flightJson) {
$flightCollection->push($this->buildFlight($flightJson));
}
return $flightCollection;
}
public function buildFlight($flightJson)
{
$flight = new Flight();
// add properties
return $flight;
}
}
The factory will return a Collection which is verry usefull because it contains usefull methods, or you can return an array.
In this example I used a curl library https://github.com/ixudra/curl but it can be replaced with native php or other libraries.
Then you can use by injecting the FlightService in your controllers.
P.S: Code not tested but represents a possible approach
I'm migrating an old app developed in Yii1 to Yii2.
I used to have a array in the controller that was storing all the variables that I would need to send to the frontend as a JavaScript:
public $jsVars;
public function toJSObject($params){
$this->jsVars = array_merge($this->jsVars, $params);
}
private function printJSVarsObject(){
//convert my php array into a js json object
}
When I needed a variable to be exposed in Javascript, I would just use $this->toJSObject, in the View or in the Controller.
Then, in the controller I also used to have:
public function beforeRender($view){
$this->printJSVarsObject();
}
In Yii2, I had to configure the View component with a custom View and then attach an event:
namespace app\classes;
use yii\base\Event;
use yii\helpers\Json;
Event::on(\yii\web\View::className(), \yii\web\View::EVENT_END_BODY, function($event) {
$event->sender->registerJSVars();
});
class View extends \yii\web\View {
public $jsVars = [];
public function addJsParam($param){
$this->jsVars = array_merge($this->jsVars, $param);
}
public function registerJSVars() {
$this->registerJs(
"var AppOptions= " . Json::htmlEncode($this->jsVars) . ";",
View::POS_END,
'acn_options'
);
}
}
But, having the event outside the class seems weird to me. Also, while I'm in the controller, I won't be able to use my former approach using this method.
Obviously, I'm missing something, or my approach is just incorrect.
How do you guys do that?
If you're trying to access properties of the controller from a view (see above comments!), you can use;
$this->context
to return an instance of the currently used controller from within the view file. So to access your beforeRender() method you would just use
$this->context->beforeRender()
I have built laravel applications in Laravel 4 and Laravel 5, but I decided this time to write all my tests first, having never previously written tests at all for trivial apps.
Here is my Account class - for illustration
class Account extends Model
{
protected $customer_id;
protected $bookmaker_id;
protected $balance;
protected $profit;
public function __construct($customer_id, $bookmaker_id, $balance, $profit) {
$this->customer_id = $customer_id;
$this->bookmaker_id = $bookmaker_id;
$this->balance = $balance;
$this->profit = $profit;
}
}
So all my unit tests run fine:
My route is set up correctly to the page I want to display
Route::get('/accounts', 'AccountController#index');
but this is where it goes wrong. Actually trying to run a page to get a list of accounts is troublesome. I know there is more to do with the controller class but here is what I have.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Account;
class AccountController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$accounts = Account::all();
return view('account.index', compact('accounts'));
}
}
Then I get this error -
ErrorException in Account.php line 14:
Missing argument 1 for App\Account::__construct(), called in /Applications/MAMP/htdocs/mb-app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 665 and defined
Can someone tell me how I should be setting up my controller please? Until I added the __construct() for my unit tests this was all going ok.
Thanks.
By using __construct, it expects arguments any time you initialize it. So instead, you'd use
$accountModel = new Account($customer_id, $bookmaker_id, $balance, $profit);
$accounts = $accountModel->all();
If you want to use those variables for creating a new model, look into $fillable.