I have some issues with Laravel5.
I got multiple domains linked to single application, but each domain can have multiple languages. Locale string should not appear until different language is selected for domain.
Maybe some one has experience with this.
etc.:
domain.com/home
domain.net
domain.lt/pagrindinis
domain.lt/en/home
I finally found solution:
On app.php i made custom array for locations:
'domains' => [
'domain_1' => [
'locales' => ['en', 'lt'],
'locale' => 'lt' // default locale for this domain
],
'domain_2' => [
'locales' => ['ru', 'en']
'locale' => 'ru',
],
];
and in route service provider.
/**
* Handle app requests
*
* #param Router $router
* #param Request $request
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function map(Router $router, Request $request)
{
$locale = $this->getLocaleByDomain($request);
$requestLocale = $request->segment(1);
$options = [
'namespace' => $this->namespace
];
if (in_array($requestLocale, Config::get('app.domains')[$request->getHost()]['locales'])) {
$locale = $requestLocale;
$options = array_merge(
$options,
[
'prefix' => $locale
]
);
}
app()->setLocale($locale);
$router->group($options, function ($router) {
require app_path('Http/routes.php');
});
}
/**
* Retrieve locale by domain
*
* #param $request
* #return mixed
*/
protected function getLocaleByDomain($request)
{
$locale = Config::get('app.fallback_locale');
if (array_key_exists($request->getHost(), Config::get('app.domains'))) {
$locale = Config::get('app.domains')[$request->getHost()]['locale'];
}
return $locale;
}
Routes.php file contains:
$router->get(trans('routes.contacts'),
[
'as' => 'contacts',
'uses' => 'PagesController#contacts'
]
);
So what i reached is multiple domains, with multiple languages and pretty nice SEO url's for every locale. Maybe anyone can make some other ideas?
Related
I need to get my data with pagination when I use collection.
Couldn't find any way, and nothing works that written on documents.
Here's my controller;
...
$data = $process->paginate(30);
$data = OrderResource::collection($data);
And here's my resource:
<?php
namespace App\Http\Resources;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Resources\Json\JsonResource;
class OrderResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
$user = Auth::user();
return [
"id" => $this->id,
"customer" => $this->customer,
"vehicle" => $this->vehicle,
"basket" => $this->basket,
"total" => money_formatter($this->total),
"discount" => $this->discount,
"net_total" => money_formatter($this->net_total),
"status" => $this->status,
"payment_type" => $this->payment_type,
"main_name" => $this->vehicle->fleet_id ? $this->vehicle->fleet->title : ($this->customer->company_id ? $this->customer->company->title : $this->customer->fullname),
"sub_name" => $this->vehicle->fleet_id ? ($this->customer->company_id ? $this->customer->company->title : $this->customer->fullname) : '',
"created_at" => Carbon::parse($this->created_at)->formatLocalized('%a, %d %B %Y'),
];
}
}
You can add a macro inside your AppServiceProvider.php for this, inside the boot method.
/**
* Paginate a standard Laravel Collection.
*
* #param int $perPage
* #param int $total
* #param int $page
* #param string $pageName
* #return array
*/
Collection::macro('paginate', function ($perPage = 15, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
And then you can use it like this (assuming $data is a regular laravel collection)
$data = $data->paginate(50);
dd($data);
You can't add any metadata (pagination links) with the collection method. First create a ResourceCollection with php artisan make:resource -c OrderCollection.
Then, in that newly created file, you can do the following.
class OrderCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
$collection = [
'data' => OrderResource::collection($this->collection)
];
if ($this->resource instanceof \Illuminate\Pagination\LengthAwarePaginator) {
$collection['pagination'] = [
'current_page' => $this->resource->currentPage(),
'last_page' => $this->resource->lastPage(),
'first_page_url' => $this->resource->url(1),
'last_page_url' => $this->resource->url($this->resource->lastPage()),
'prev_page_url' => $this->resource->previousPageUrl(),
'next_page_url' => $this->resource->nextPageUrl(),
'from' => $this->resource->firstItem(),
'to' => $this->resource->lastItem(),
'total' => $this->resource->total(),
'per_page' => $this->resource->perPage(),
'path' => $this->resource->path(),
];
}
return $collection;
}
}
dd(json_encode(new OrderCollection(Order::paginate(3)), JSON_PRETTY_PRINT));
I'm making an API using Eloquent: API Resources.
This is my article Resource:
class Article extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'slug' => $this->slug,
'name' => $this->name,
'comments' => $this->when($this->showComments(), function () {
$comments = config('eblogger.models.comment')::where([
'commentable_type' => get_class($this),
'commentable_id' => $this->id,
'parent_id' => 0,
])->orderBy('created_at', 'desc')->get();
$paginator = makePaginationCollection($comments, route('blog.comments'));
return CommentResource::collection($paginator);
}),
];
}
}
It's an article with comments.
I want to get pagination with my comments, so i call a custom helper
function makePaginationCollection($collection, $path)
{
$request = request();
$page = request('page', 1);
$perPage = config('settings.items_by_pages');
$paginate = new \Illuminate\Pagination\LengthAwarePaginator(
$collection->forPage($page, $perPage),
$collection->count(),
$perPage,
$page,
['path' => $path]
);
return $paginate;
}
Update : this my resource collection
class CommentCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}
but when i inspect the response in the devtools, i see
I tried with CommentCollection class without success.
Do you have an idea?
Thanks
My solution
finally, thanks to #Rwd, i found this solution but I think it is possible to do better:
This is my article Resource:
public function toArray($request)
{
return [
// ...
'comments' => $this->when($this->showComments(), function() {
return new CommentCollection(
$this->comments()
->orderBy('created_at', 'desc')
->paginate(config('settings.items_by_pages'))
->withPath(route('blog.comments'))
);
})
];
}
And this is my resource collection :
public function toArray($request)
{
return [
'data' => $this->collection,
'links' => $this->resource,
'meta' => $this->resource
];
}
I'm trying to write a test unit for the route 'store' in my controller, pass a fake file to be tested too through the validator of my method, but all i got is that the data is not a file :
Illuminate\Foundation\Testing\TestResponse {
+baseResponse: Illuminate\Http\JsonResponse {
#data: "{
"message":"The given data was invalid.",
"errors":{"invoice":["The invoice must be a file."]}
}"
Code :
Test :
$data = factory('App\Domain\X\X')->raw(['creator_id' => $user->id]);
$data['invoice'] = UploadedFile::fake()->create('invoice.xlsx');
$response = $this->json('POST', route('x.store', $data));
Controller :
public function store(XXXRequest $request)
{
...
Request :
class XXXRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required',
'invoice' => 'nullable|file',
];
}
try this:
Test:
$data = factory('App\Domain\X\X')->raw(['creator_id' => $user->id]);
$data['invoice'] = UploadedFile::fake()->create('invoice.xlsx');
$response = $this->json('POST', route('x.store', $data), [
'name' => 'abc',
'invoice' => $data['invoice']
]);
Just create an UploadedFile from a local file and add it to your request:
use Illuminate\Http\UploadedFile;
$filename = public_path('tests/invoice.pdf');
$file = new UploadedFile($filename, 'invoice.pdf', 'application/pdf', filesize($filename), null, true);
$this->post('/', [
'invoice' => $file,
]);
You can read about testing file uploads here or visit official documentation
/**
* Example
*
* #test
*/
public function test_correct_file_uploading(): void
{
// Set fake storage ('local', 's3', etc)
Storage::fake('local');
$response = $this->json('POST', '/path_to_your/controller/method', [
'file' => UploadedFile::fake()->create('invoice.xlsx', 1024)
]);
// Assert response successful
$response->assertSuccessful();
// Assert the file was stored
Storage::disk('local')->assertExists('invoice.xlsx');
}
i have some problem...
here is my code..
i can't get what i swrong with my code.....
here is the error
here is my user class
this is the full DashboardController
/**
* '/home' calls this route
*
* #param none
* #return view dashboard
*/
public function index()
{
$this->permission();
$data = [
'pagetitle' => 'Dashboard',
'permission' => Session()->get('permission'),
'name' => Auth::user()->name,
];
return view('dashboard',$data);
}
/**
* Checks if session has permission in it if not they adds to it
*
* #param null
* #return null
*/
private function permission()
{
if (!Session()->has('permission')) {
$permission = User::find(Auth::user()->id)->details;
$permission_arr = [
'department' => $permission->permission_department,
'asset' => $permission->permission_asset,
'users' => $permission->permission_users,
];
Session()->put('permission', $permission_arr);
}
}
}
i have no idea how solve it..
any help would be great..
You get this kind of problem for you are getting only access of details column From your User table . Remove the details from $permission = User::find(Auth::user()->id);
private function permission(){
if (!Session()->has('permission')){
$permission = User::find(Auth::user()->id);
$permission_arr = [
'department' => $permission->permission_department,
'asset' => $permission->permission_asset,
'users' => $permission->permission_users,
];
Session()->put('permission', $permission_arr);
}
}
Note I have only remove the details object from your permission variable
PROBLEM: AJAX request not working with prefix
Website works great without language prefix. But I need it.. So before (no middleware) and ajax post to domain.com/entitlement worked great.
However, when posting with prefix (domain.com/en/entitlement) and having the pre-fix middleware on throws an error MethodNotAllowedHttpException in RouteCollection.php line 219:
The stackoverflow posts I have seen on prefix routing are focusing on GET related issues. Like Laravel 5 route prefix. I have a POST issue (the GET works fine)
Any ideas?
ROUTES
Route::group(['middleware' => ['web']], function () {
Route::group(
[
'prefix' => LaravelLocalization::setLocale(),
'middleware' => [ 'localeSessionRedirect', 'localizationRedirect' ]
],
function()
{
Route::get('/', array(
'as' => 'home',
'uses' => 'HomeController#getHome'
));
Route::post('/entitlement', array(
'as' => 'entitlement-post',
'uses' => 'HomeController#postEntlitment'
));
}
}
AJAX REQUEST
$.ajax({
type: 'POST',
url: '/entitlement', --> Becomes domain.com/en/entitlement
data: data,
dataType:'json',
beforeSend: function() {
},
...
LocalizationSessionRedirect
<?php namespace Mcamara\LaravelLocalization\Middleware;
use Illuminate\Http\RedirectResponse;
use Closure;
class LocaleSessionRedirect {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle( $request, Closure $next )
{
$params = explode('/', $request->path());
$locale = session('locale', false);
if ( count($params) > 0 && $locale = app('laravellocalization')->checkLocaleInSupportedLocales($params[ 0 ]) )
{
session([ 'locale' => $params[ 0 ] ]);
return $next($request);
}
if ( $locale && app('laravellocalization')->checkLocaleInSupportedLocales($locale) && !( app('laravellocalization')->getDefaultLocale() === $locale && app('laravellocalization')->hideDefaultLocaleInURL() ) )
{
app('session')->reflash();
$redirection = app('laravellocalization')->getLocalizedURL($locale);
return new RedirectResponse($redirection, 302, [ 'Vary' => 'Accept-Language' ]);
}
return $next($request);
}
}
Thanks to tptcat the answer is to take out middleware of Mcmara's redirect.
UPDATED ROUTE
Route::group(
[
'prefix' => LaravelLocalization::setLocale(),
// 'middleware' => [ 'localeSessionRedirect', 'localizationRedirect' ] --> Not included
],
function()
{