I have a group route like this
PHP LARAVEL 9
/**
* ACCOMODATIONS
*/
Route::controller(AccomodationsController::class)->group(function () {
Route::prefix('accomodations')->group(function () {
Route::GET('/', 'index');
Route::GET('/italy', 'index');
Route::GET('/greece', 'index');
});
});
In the controller side I want to obtain the accomodations part and the italy greece part without slashes. I'm doing like this
PHP LARAVEL 9
class AccomodationsController extends Controller
{
public function index(request $request){
$listType = [
'type' => trim($request->route()->getPrefix(), '/'),
'route' => request()->segment(count(request()->segments()))
];
dd($listType);
);
}
/*
http://example.com/accomodations outputs
array [
"type" => "accomodations"
"route" => ""
]
/*
/*
http://example.com/accomodations/italy outputs
array [
"type" => "accomodations"
"route" => "italy"
]
*/
/*
http://example.com/accomodations/greece outputs
array [
"type" => "accomodations"
"route" => "greece"
]
*/
This works but the way I'm manipulating the request in $listType seems a little bloated to me, is there a cleaner way in laravel?
Use parameterized route for same method.
Routes
Route::controller(AccomodationsController::class)->group(function () {
Route::prefix('accomodations')->group(function () {
Route::GET('/{destination}', 'index');
});
});
Controller
public function index(Request $request, $destination){
$listType = [
'type' => trim($request->route()->getPrefix(), '/'),
'route' => $destination
];
dd($listType);
);
If your destination is optional you can use optional parameter
Edit 1:
Route with Optional Parameter
Route::controller(AccomodationsController::class)->group(function () {
Route::prefix('accomodations')->group(function () {
Route::GET('/{destination?}', 'index');
});
});
Controller with Optional parameter
public function index(Request $request, $destination=''){
$listType = [
'type' => trim($request->route()->getPrefix(), '/'),
'route' => $destination
];
dd($listType);
);
you can assign any value (null, string, int, etc.) to the destination variable just like the default function argument in PHP.
Related
how change this:
site/faq
to this:
site/faq?festival=nouroz98&id=100000&data=information
this is the FestivalRule class
class FestivalRule implements UrlRuleInterface
{
public $pattern;
public $route;
public function createUrl($manager, $route, $params)
{
return [$route, $params];
}
public function parseRequest($manager, $request)
{
if(!empty($request->getQueryParams())){
if($request->getPathInfo() == 'site/faq'){
return [
'site/faq',
$request->getQueryParams()
];
}
}else{
return [
'site/faq',
[
'festival' => 'nouroze99',
'id' => '10000',
'data' => 'from db',
]
];
}
return false;
}
}
this is the urlmanager config:
'rules' => [
[
'class' => 'app\components\FestivalRule',
'pattern' => 'site/faq/<festival:\w+>/<id:\d+>/<data:\w+>',
'route' => 'site/faq',
],
I want if the URL requested without any parameters i changing that with parameters but i can't place the parameters in URL.
all parameters sent but i wanted url changes too (parameters shows in URL)!
I am testing an eager loading relationship which contains many to many relations. Right now I have the queries and attachments within the test. I'm wondering if there is a way to move them into the factory, rather than including it as part of your test. This would limit the size of the test and then these relations could be created and used every time a film factory is created.
test
public function grabFilmTest()
{
$film = factory(Film::class)->create();
$categories = Category::where('main-cat', 'Science')->where('sub-cat', 'Fiction')->first();
$languages = Languages::where('name', 'english')->first();
$film->categories()->attach($categories->id);
$film->languages()->attach($languages->id);
$response = $this->json('GET', '/film/' . $film->id)
->assertStatus(200);
$response
->assertExactJson([
'id' => $film->id,
'name' => $film->name,
'description' => $film->description,
'categories' => $film->categories->toArray(),
'languages' => $film->languages->toArray()
}
filmFactory
$factory->define(\App\Models\Film::class, function (Faker $faker){
return [
'id' => $faker->uuid,
'name' => $faker->text,
'description' => $faker->paragraph,
];
});
If anyone could help with how i could do this or an example it would be great :D
You could use factory states and factory callbacks.
$factory->define(\App\Models\Film::class, function (Faker $faker){
return [
'id' => $faker->uuid,
'name' => $faker->text,
'description' => $faker->paragraph,
];
});
$factory->define(\App\Models\Category::class, function (Faker $faker){
return [
// Category fields
];
});
$factory->define(\App\Models\Language::class, function (Faker $faker){
return [
// Language fields
];
});
$factory->afterCreatingState(\App\Models\Film::class, 'with-category', function (\App\Models\Film $film) {
$category = factory(\App\Models\Category::class)->create();
$film->categories()->attach($category->id);
});
$factory->afterCreatingState(\App\Models\Film::class, 'with-language', function (\App\Models\Film $film) {
$language = factory(\App\Models\Language::class)->create();
$film->categories()->attach($language->id);
});
Then you can use in tests like this:
public function grabFilmTest()
{
$film = factory(Film::class)->create();
$filmWithCategory = factory(Film::class)->state('with-category')->create();
$filmWithLanguage = factory(Film::class)->state('with-language')->create();
$filmWithCategoryAnLanguage = factory(Film::class)->states(['with-category', 'with-language'])->create();
// ...
}
PS: I don't recommend using existing data. From experience, I can tell you that can become really painful.
You can use factory callbacks to do it in the factory file:
<?php
use \App\Models\Film;
use \App\Models\Category;
use \App\Models\Languages;
$factory->define(Film::class, function(Faker $faker){
return [
'id' => $faker->uuid,
'name' => $faker->text,
'description' => $faker->paragraph,
];
});
$factory->afterCreating(Film::class, function(Film $film, Faker $faker) {
$category = Category::where('main-cat', 'Science')->where('sub-cat', 'Fiction')->first();
$language = Languages::where('name', 'english')->first();
$film->categories()->attach($category);
$film->languages()->attach($language);
});
The following route works fine and the method can loop through the items:
http://localhost/library/api/books
$app->get('/api/books', 'Book:getBooks');
The class:
class Book {
:
:
public function __construct($container) {
$this->container = $container;
}
public function getBooks($request, $response) {
:
:
echo '{"book": ' . json_encode($books) . '}';
}
public function getBook($id) {
echo json_encode($id);
}
}
Calling the method with route pattern identified by 'id' as follows, returns nothing (empty $id):
http://localhost/library/api/books/10
$app->get('/api/books/{id}', 'Book:getBook');
It seems like 'id' won't pass.
How to handle correctly route pattern by identifier?
As I said in the comments, please let us know what the dev console says for instance in chrome under the category console and network.
I am not sure why you choose to create your routes like that, but I would create them following way (which also looks more tidy) :
Route::group(['prefix' => 'book'], function ()
{
Route::get('/', ['as' => 'index', 'uses' => 'BookController#index']);
Route::get('new', ['as' => 'new', 'uses' => 'BookController#new']);
Route::get('show/{bookID}', ['as' => 'show', 'uses' => 'BookController#show']);
Route::get('edit/{bookID}', ['as' => 'edit', 'uses' => 'BookController#edit']);
Route::post('create', ['as' => 'create', 'uses' => 'BookController#create']);
Route::post('update', ['as' => 'update', 'uses' => 'BookController#update']);
Route::delete('destroy/{deviceID}', ['as' => 'destroy', 'uses' => 'BookController#destroy']);
});
The BookController would look like this then:
class BookController extends Controller
{
// this shows all books and adds a pagination of 15 items, which you can easily increase or decrease
public function index()
{
$books = DB::table('books')->paginate(15);
return view('books.index', compact('books');
}
public function new()
{
$book = new Book;
return view('books.new', [
'books' => $books,
'type' => 'new'
]);
}
public function create(Request $request)
{
$this->validate($request, Book::$rules); // I put the rules inside of the Book Model, but you could just add them here aswell
$data = $request->all();
$book = new Book();
$book->fill($data);
if($book->save())
{
return redirect()->route('new')->with('success', 'success.');
}
else
{
return redirect()->route('new')->with('error', 'Error.')->withInput();
}
public function edit(Request $request, $bookID = 0)
{
$books = Book::all();
$newBook = new Book;
$book = Book::find($bookID);
if(is_null($book))
{
$books = Device::paginate(10); // paginate if you like to
return view('books.index', [
'books' => $books,
'errorNoBook' => 'No BOok'
]);
}
else
{
$bookID = $book->id;
}
return view('books.edit', [
'allBooks' => $allBooks,
'new' => $new,
'book' => $book,
]);
}
}
The following is a simple working solution that I found:
:
:
public function getBook($request, $response) {
$route = $request->getAttribute('route'); // route object
$id = $route->getArgument('id'); // route object identifier
$book = $this->db->table('books')->where('id', $id)->first();
echo json_encode($book);
}
i try to build a custom POST route for ReST API in cakephp 3, but when i want to connect to the url i got result:
The view for CalculatedpricesController::getCosts() was not found.
My url to connect to ReST like this :
http://localhost/test/api/calculatedprices/getCosts
here's the route code:
Router::scope('/', function (RouteBuilder $routes) {
Router::prefix('api', function ($routes) {
$routes->extensions(['json', 'xml']);
$routes->resources('Calculatedprices', [
'map' => [
'getCosts' => [
'action' => 'getCosts',
'method' => 'POST'
]
]
]);
});
$routes->fallbacks(DashedRoute::class);
});
here's the controller code:
namespace App\Controller\Api;
use App\Controller\Api\AppController;
/**
* Calculatedprices Controller
*
* #property \App\Model\Table\CalculatedpricesTable $Calculatedprices
*/
class CalculatedpricesController extends AppController
{
public function getCosts(){
$originIdCity = $this->request->query('originCity');
$originIdSub = $this->request->query('originSub');
$courierId = $this->request->query('courierId');
$serviceId = $this->request->query('serviceId');
$conditions = array('origin_city_id' => $originIdCity,
'courier_id' => $courierId,
'service_id' => $serviceId
);
if($originIdSub == ''){
$condition = 'origin_subdistrict_id IS NULL';
array_push($conditions,$condition);
} else{
$conditions['origin_subdistrict_id'] = $originIdSub;
}
$calculatedprices = $this->Calculatedprices->find('all', array(
'conditions' => $conditions
));
$this->set([
'calculatedprices' => $calculatedprices,
'_serialize' => ['calculatedprices']
]);
}
}
My question is based on how I can pass the $searchResult in my Controller class so as I can use it to display the search result
This is my Controller
class SearchController extends Controller {
public function getHome($searchFor = null) {
$result = SearchPost::all();
return view('home', ['resulta' => $result]);
}
public function postSearch(Request $request) {
$this->validate($request, [
'searchString' => 'required|max:20|alpha',
]);
$searchFor = $request['searchString'];
//Connection with model(SearchPost) to search
$searchResult = SearchPost::search($searchFor);
return redirect()->route('home', ['searchFor' => $searchFor]);
}
}
Routes:
Route::get('/{searchFor?}', [
'uses' => 'SearchController#getHome',
'as' => 'home'
]);
Route::post('/search', [
'uses' => 'SearchController#postSearch',
'as' => 'search'
]);
Try the following methods:
return redirect(route('home', ['searchFor' => $searchFor]));
Or
return redirect('home')->with('home', ['searchFor' => $searchFor]);