اذهب إلى المحتوى

Sam Ahw

الأعضاء
  • المساهمات

    1388
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    16

كل منشورات العضو Sam Ahw

  1. يتم تحويل العلامة / إلى %2F ضمن الترميز المستخدم في المسارات والذي يدعى percent-encoding، والسبب في هذه المشكلة أنه عند التحديث إلى نسخة Angular 1.6 يجب تغيير المسارات الافتراضية الموجودة ضمن خدمة المسارات $location أي استخدام locationProvider لتصبح بالشكل التالي: appModule.config(['$locationProvider', function($locationProvider) { $locationProvider.hashPrefix(''); }]); وأيضاً يوجد حل آخر من طرف العميل بإضافة العلامة ! قبل مسار التوجيه لتصبح بالشكل التالي: بدلاً من #/path/new تصبح كالتالي: #!/path/new
  2. إن علامة النجمة * تستخدم للتحقق من قيم عناصر المصفوفة وليس المصفوفة بحد ذاتها، لذلك عند إرسال مصفوفة فارغة سيتم تطبيق شروط التحقق على العناصر وفي حال كانت فارغة فإنها بالتالي لا تحوي عناصر حتى يتم التحقق منها ولذلك لن يفشل التحقق أو الدخول وتنفيذ الكود داخل الشرط. لذلك يجب إضافة اسم المتغيّر أو المصفوفة بشكل منفصل عن العناصر ودون استخدام علامة النجمة للدلالة على المصفوفة نفسها بالشكل التالي: $validator = Validator::make($request->all(), [ "attributes" => "required|array|min:3", "attributes.*" => "required|string|distinct|min:3", ]); وبهذا الشكل سيتم إجراء التحقق على المصفوفة بمجموعة من القيود، وعلى عناصر هذه المصفوفة بقيود أخرى.
  3. عند إضافة تابع جديد لأي من الموارد resources يجب إضافة المسار الخاص بهذا التابع بشكل منفصل ووضعه قبل تعريف المورد، أي بالشكل التالي: Route::get('any/newMethod', 'AnyController@newMethod'); Route::resource('any', 'AnyController'); ومن المهم وضع التابع قبل تعريف ال resource وإلا سيظهر الخطأ التالي: "No query results for model"
  4. للحصول على آخر سجل لكل قسم حسب أرقام الأقسام الفريدة، يمكن تنفيذ الاستعلام التالي: select s.* from deps s left join deps s1 on s.department_id = s1.department_id and s.created_at < s1.created_at where s1.department_id is null وعن طريق Eloquent: DB::table('deps as s') ->select('s.*') ->leftJoin('deps as s1', function ($join) { $join->on('s.department_id', '=', 's1.department_id') ->whereRaw(DB::raw('s.created_at < s1.created_at')); }) ->whereNull('s1.department_id') ->get(); وبهذه الطريقة سيتم عند استعادة كل سجل مقارنته مع بقية السجلات التي تنتمي للقسم المحدد و أخذ القيمة الأصغر من التاريخ الموجود ضمن العمود created_at
  5. لارافيل تقدّم إمكانية الحصول على عنوان IP من خلال ال request القادم من العميل إلى الخادم، ويمكن تنفيذ ذلك باتباع عدة طرق: $clientIP = request()->ip(); dd($clientIP); أو من خلال الغرض request بشكل مباشر ضمن المتحكّم: public function index(Request $request) { dd($request->ip()); } وأيضاً يمكنك استعادة القيمة من \Request::ip() وتخزينها في متحوّل: $clientIP = \Request::ip(); dd($clientIP); أو $clientIP = \Request::getClientIp(true); dd($clientIP);
  6. عند استخدام التوابع أي (الأقواس) عند الإشارة لعلاقة، فإنك تقوم باستدعاء التابع الذي قام بدوره بتعريف العلاقة: public function clients(){ return $this->hasMany('Clients'); } وبالتالي عند كتابة $store->clients() فإننا نستحدث نسخة من Illuminate\Database\Eloquent\Relations\HasMany. ويتم استخدامها في العلاقات عندما نريد إضافة بعض التفاصيل للاستعلام، مثلاً: $clients = $store->clients()->where('balance', '>', 2000)->get(); أما العلاقات الديناميكية في لارافيل والتي يمكن الوصول لها بشكل مباشر $model->relation فإنها تقوم باستدعاء Illuminate\Database\Eloquent\Model والذي بدوره يقوم بجلب الصفات attributes الموافقة لهذه العلاقة. ولذلك نجد عند تنفيذ كل منها: $model->relation() تعيد غرض من العلاقة Object $model->relation تعيد نتيجة العلاقة نفسها
  7. الطريقة العامة للتأكد من السجلات المرتبطة والمستخدمة من قبل نسخة php 7.2 هي بالتحقق من عدد السجلات: if (count($model->relation)) { // أي يوجد سجلات } وأصبح من الممكن أيضاً التحقق إما عن طريق الطريقة السابقة أو باستخدام Eloquent، ففي العلاقات الأحادية مثل: hasOne, belongsTo, morphTo, morphOne يمكن تنفيذ التالي: // لا يوجد مودل موافق $model->relation; // null count($model->relation); // 0 أي false // يوجد مودل مطابق $model->relation; count($model->relation); // 1 أي true أما في العلاقات المتعددة مثل: hasMany, belongsToMany, morphMany, morphToMany, morphByMany يمكن تنفيذ التالي: // لا يوجد مجموعة مرتبطة $model->relation; // المجموعة التي لا تحوي سجلات مرتبطة ستعطي القيمة true count($model->relation); // 0 أي false // يوجد سجلات مرتبطة $model->relation; // المجموعة التي تحوي عنصر واحد أو أكثر ستعطي true أيضاً count($model->relation); ففي العلاقات المتعددة يجب الانتباه إلى قيم true لأنه عند وجود مجموعة لديها مجموعة مرتبطة بها حتى ولو كانت هذه المجموعة لا تحوي سجلات ستعطي القيمة true.
  8. يمكن تبسيط العملية بالتسهيلات الموجودة في لارافيل لدعم تعدد اللغات وبوضع مسار خاص بكل لغة، ضمن المجلّد app/lang يمكننا إضافة ملف routes.php خاص بكل لغة، فبفرض لدينا 3 لغات نقوم بإنشاء 3 ملفات في 3 مجلدات مختلفة. وضمن كل ملف نضع الترجمة الخاصة باللغة على شكل مصفوفة من المفاتيح والقيم key => value بالشكل التالي: <?php // app/lang/ar/routes.php ضمن المسار return array( 'contact' => 'تواصل معنا', 'about' => 'من نحن' ); وبنفس الطريقة لبقية اللغات. ثم نقوم بإضافة اللغات على ملف app/config/app.php : 'locale' => 'ar', => نقوم بتعريف اللغة الافتراضية للموقع //ثم نقوم بإضافة اللغات الأخرى 'alt_langs' => array ('en', 'gr'), /** * Prefix of selected locale - leave empty (set in runtime) */ 'locale_prefix' => '', حيث يجب وضع اسم اللغة ضمن alt_langs بشكل مطابق لأسماء الملفات التي قمنا بإنشائها. وأخيراً، ضمن الملف app/routes.php يجب أن يكون بشكل مشابه للتالي: <?php if (in_array(Request::segment(1), Config::get('app.alt_langs'))) { App::setLocale(Request::segment(1)); Config::set('app.locale_prefix', Request::segment(1)); } foreach(Lang::get('routes') as $k => $v) { Route::pattern($k, $v); } Route::group(array('prefix' => Config::get('app.locale_prefix')), function() { Route::get( '/', function () { return "Home- ".App::getLocale(); } ); Route::get( '/{contact}/', function () { return "contact".App::getLocale(); } ); Route::get( '/{about}/', function () { return "about".App::getLocale(); } ); }); حيث سيتم ترجمة /{contact}/ و باقي المسارات حسب prefix التي قمنا بتعريفها ضمن اللغة والمسار.
  9. دالة power في جافا تابعة للمكتبة Math ولها الشكل التالي: Math.pow(x, y); x هي الرقم الأساس، و y هي القوّة. فيمكن استخدامها بالشكل التالي: double nan = Double.NaN; double result; result = Math.pow(2, nan); System.out.println(result); //النتيحة هي NaN result = Math.pow(1254, 0); System.out.println(result); //النتيجة 1 result = Math.pow(5, 1); System.out.println(result); //النتيجة 5 ويجب التأكد من تضمين المكتبة قبل استخدامها: import java.lang.Math; // importing java.lang package
  10. من الممكن أن يكون قد تم تحديث Apache2 أيضاً إلى النسخة 2.4 أو الأحدث، ويمكنك التأكد من ذلك عن طريق تنفيذ الأمر التالي: $ apache2 -v وإن كان كذلك، يجب عليك إجراء بعض التعديلات بسبب التغييرات الحاصلة في النسخ الحديثة والتي لم تعد تتوافق مع مشروعك. فيجب أن تقوم بتعديل إعدادات vshosts: من هذا الشكل: Options Indexes FollowSymLinks MultiViews لكي تصبح كالتالي: Options +Indexes +FollowSymLinks +MultiViews وأيضاً يجب إجراء التعديلات التالية على سماحيات apache: Order allow,deny Allow from all لتصبح بالشكل التالي: Require all granted وأخيراً يجب التأكد من الصلاحيات من جديد بعد التحديث بأن تكون مشابهة للتالي: $ sudo chmod -R gu+w storage $ sudo chmod -R guo+w storage $ sudo chmod -R gu+w bootstrap/cache $ sudo chmod -R guo+w bootstrap/cache
  11. يوجد طريقتين لتنفيذ ذلك: أولاً: يجب وضع الملف .htaccess في المجلّد الجذر root للمشروع، ففي حال لم يكن موجود يجب أن تقوم بنقله أو إنشاء الملف. وعادةً يكون ضمن public_html. ثم يجب التأكد أنه يحوي الكود التالي: <IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ public/$1 [L] </IfModule> الآن يمكنك الوصول للملفات دون الحاجة لوجود المسار /public/index.php/. ثانياً: يمكنك تنفيذ ذلك عن طريق نقل محتويات المجلّد public جميعها إلى المجلّد الجذر في الاستضافة، ثم يجب القيام بالتغييرات التالية في ملف bootstrap/paths.php: 'app' => __DIR__.'/../app', 'public' => __DIR__.'/../public', يجب أن تصبح بالشكل التالي: 'app' => __DIR__.'/../app', 'public' => __DIR__.'/../../', ثم في ملف index.php: require __DIR__.'/../bootstrap/autoload.php'; $app = require_once __DIR__.'/../bootstrap/start.php'; يجب أن تصبح كالتالي: require __DIR__.'/root_folder/bootstrap/autoload.php'; $app = require_once __DIR__.'/root_folder/bootstrap/start.php'; مع استبدال اسم المجلّد root_folder باسم المجلّد الجذر الذي لديك.
  12. يجب التأكد من تعديل قيمة default لتشير إلى postgre ضمن ملف app/config/database.php: 'default' => 'postgres', وفي حال بقي الخطأ التالي بالظهور: [PDOException] could not find driver يجب التأكد من إضافة الإعدادات اللازمة في ملف php.ini وتثبيت الإضافة pdo_pgsql.so و pgsql.so وتفعيلهما. وفي حال كان نظام التشغيل ويندوز يمكن التوجه لملف PHP وإلغاء التعليق على الإضافات التالية: extension=pdo_pgsql.so extension=pgsql.so أما لنظام تشغيل Ubuntu: sudo apt-get install php7.0-pgsql مع تعديل نسخة php بالنسخة الموجودة لديك. وأخيراً، بعد هذه التعديلات، يجب التأكد من القيم الموضوعة ضمن ملف .env في لارافيل بالشكل الموافق لإعدادات قاعدة البيانات. ومن الممكن أيضاً الحاجة لإضافة متغيرات البيئة Environment Variables وإضافة المسار الخاص بـ bin التابع ل postgreSql على جهازك.
  13. يظهر هذا الخطأ بعد التحقق والمشكلة هنا في إعدادات الجلسات session في مشروعك. يجب التأكد من أن session driver يقوم بالحفظ ضمن ملف file وليس array. فبشكل افتراضي يمكن أن يتم استخدام المصفوفات للتجربة فقط ولكن عند الحاجة لنشر المشروع يجب تغييرها ليتم حفظ الجلسات ضمن ملف بدلاً من ذلك. والتأكد أيضاً من وجود الملف ومساره الصحيح والصلاحيات على هذا الملف بأن يكون قابل للكتابة: is_writable(config('session.files')) وأيضاً يجب التحقق من الكود الموجود ضمن config/session.php ونوع الاتصال في حال كان HTTPS (SSL/TLS) للنطاق الذي يحوي المشروع يجب تعديل sessions.secure إلى القيمة true.
  14. من الممكن تكون طريقة إدخال السجلات خاطئة وغالباً عند إدخال عدّة سجلات في نفس الوقت تحدث مشكلة نتيجة تضارب timestamps الذي تستخدمه لارافيل في قواعد البيانات، يمكنك تجربة الكود التالي لإدخال عدة سجلات دفعة واحدة: $json_array=array_map(function ($a) { return array_merge($a,['created_at'=> Carbon::now(),'updated_at'=> Carbon::now()] ); }, $json_array); Model::insert($json_array); أو إنشاء تابع createMany: /** * * @param array $records * @return \Illuminate\Database\Eloquent\Collection */ public function createMany(array $records) { $instances = $this->related->newCollection(); foreach ($records as $record) { $instances->push($this->create($record)); } return $instances; }
  15. يوجد عدّة طرق لمشاركة البيانات بين views في لارافيل: فيمكنك تنفيذ ذلك عن طريق استخدام متحكم رئيسي تضع فيه جميع البيانات أو العمليات العامة global التي ترغب بمشاركتها، ثم تستطيع الوصول إليها عن طريق باقي المتحكمات بالوراثة، كالتالي: class BaseController extends Controller { public function __construct() { /نضع البيانات التي نرغب بمشاركتها $user = User::all(); // نقوم باستخدام share View::share('user', $user); } } الطريقة الثانية هي باستخدام الفلاتر Filter، فيقوم لارافيل بتنفيذ الفلتر قبل الطلب request عن طريق App:before: App::before(function($request) { View::share('user', User::all()); }); أو يمكنك كتابة الفلتر الخاص بك أيضاً: Route::filter('user-filter', function() { View::share('user', User::all()); }); الطريقة الثالثة هي باستخدام وسيط middleware ووضعه في جميع المسارات التي ستتشارك البيانات كالتالي: Route::group(['middleware' => 'SomeMiddleware'], function(){ // نضع هنا المسارات ضمن مجموعة واحدة تتشارك البيانات }); class SomeMiddleware { public function handle($request) { \View::share('user', auth()->user()); } } وأخيراً، يمكنك أيضاً استخدام viewComposer في لارافيل، فنقوم بإنشاء مجلّد خاص ضمن المسار App\Http\ViewComposers، ونضيف على serviceProvider: namespace App\Providers; use Illuminate\Support\ServiceProvider; class ViewComposerServiceProvider extends ServiceProvider { public function boot() { view()->composer("ViewName","App\Http\ViewComposers\TestViewComposer"); } } ثم نقوم بإضافة الصف TestViewComposer ضمن config/app.php: namespace App\Http\ViewComposers; use Illuminate\Contracts\View\View; class TestViewComposer { public function compose(View $view) { $view->with('ViewComposerTestVariable', "Calling with View Composer Provider"); } } وعندها يمكننا استدعاء البيانات بأي view كالتالي: {{$ViewComposerTestVariable}}
  16. عند ظهور هذا الخطأ يجب عليك تغيير الملكية على مجلّد المشروع، أي يجب عليك وضع المستخدم الذي قمت بتسجيل الدخول منه إلى النظام كمالك لهذا المجلّد وخادم الويب www-data أو apache ضمن المجموعة، كالتالي: sudo chown -R $USER:www-data storage sudo chown -R $USER:www-data bootstrap/cache sudo chown -R $USER:www-data bootstrap/logs والصلاحيات على المجلّد: chmod -R 775 storage chmod -R 775 bootstrap/cache ولكن تختلف المجموعات لخادم الويب والمستخدم تبعاً لنظام التشغيل لديك، لمعرفتها يمكنك إجراء الأمر التالي على nginx: ps aux|grep nginx|grep -v grep أما في apache: ps aux | egrep '(apache|httpd)' ملاحظة: لا يجب إعطاء صلاحيات أكثر من 775، فعلى سبيل المثال إعطاء صلاحيات من الشكل 777 عند نشر المشروع قد يسبب بعض المشاكل الأمنية. والصلاحيات 775 تكفي ومعناها كالتالي: 7 - المالك يستطيع الكتابة 7 - المجموعة تستطيع الكتابة 5 - وأي شيء غيرهم لا يستطيع الكتابة وفي حال لم يتم حل المشكلة، يمكن التجربة بتعديل الملف Vagrant كالتالي: config.vm.synced_folder "./app","/var/www/", create:true, :owner => "vagrant", :group => "www-data", :mount_options => ["dmode=775","fmode=664"]
  17. يمكن الاستماع للحدث 'illuminate.query' عند الحاجة لإجرائها على أكثر من استعلام وللسهولة. كالتالي: Event::listen('illuminate.query', function($query, $params, $time, $conn) { dd(array($query, $params, $time, $conn)); }); DB::table('users')->get(); ويجب إضافتها قبل الاستعلامات، وعند حدوث أي استعلام على قاعدة البيانات سيتم تنفيذ محتوى التابع وطباعة مصفوفة تحوي جميع المتغيرات التي قمنا بتمريرها في التابع وبذلك يمكنك الحصول على كافة المعلومات الخاصة بهذا الاستعلام: الاستعلام نفسه - المتغيرات - توقيت الاستعلام - نوع الاتصال. وستكون نتيجتها بشكل مشابه للتالي: array(4) { [0]=> string(21) "select * from "users"" [1]=> array(0) { } [2]=> string(4) "0.94" [3]=> string(6) "sqlite" }
  18. يجب إزالة الوسيط web من مسار التوجيه، فلارافيل تقوم تلقائياً بإضافته ضمن app/Providers/RouteServiceProvider.php: protected function mapWebRoutes(Router $router) { $router->group([ 'namespace' => $this->namespace, 'middleware' => 'web', ], function ($router) { require app_path('Http/routes.php'); }); } أما إذا قمنا بشكل يدوي بإضافته فسيسبب مشاكل. ولإرسال الخطأ بعد التحقق يمكن عن طريق Redirect::back()->withErrors وإضافة الكود التالي في المتحكم لديك ليصبح: $validator = Validator::make($request->all(), [ 'fname' => 'required|max:20|min:4', 'uemail' => 'required|email', 'message' => 'required', ]); if ($validator->fails()) { $messages = $validator->messages(); return Redirect::back()->withErrors($messages)->withInput($request->all()); } ثم في صفحة blade يمكن استقبال أي خطأ كالتالي: @if ($errors->any()) <label for="fname" class="error">{{ $errors->first('fname') }}</label> @endif
  19. يمكن استخدام Request::isSecure الذي تقدمه لارافيل وإنشاء وسيط middleware بهذه الطريقة: namespace MyApp\Http\Middleware; use Closure; use Illuminate\Support\Facades\App; class HttpsProtocol { public function handle($request, Closure $next) { if (!$request->secure() && App::environment() === 'production') { return redirect()->secure($request->getRequestUri()); } return $next($request); } } وبذلك يقوم الصف HttpsProtocol بتحويل جميع الطلبات إلى Https والتي قادمة من http وأيضاً إذا كانت البيئة الحالية هي بيئة النشر، لتجنب الأخطاء بين التطوير والنشر للمشروع. ولتطبيقه نقوم أيضاً بإضافته ضمن Kernel.php: protected $middleware = [ ...... 'MyApp\Http\Middleware\HttpsProtocol' ..... ]; ووفقاً للتوثيق الرسمي، عند استخدام CDN كـ Cloudflare على سبيل المثال، سيتم تمرير X-Forwarded-Protocol إلى خادم الويب عن طريق Http وعندها سيتم الدخول في حلقة لانهائية وستبقى الصفحة تقوم بالتحديث بدون عرض محتوياتها، لذلك يجب أيضاً إضافة الكود التالي إلى الوسيط السابق: $request->setTrustedProxies( [ $request->getClientIp() ] ); لتأمين الوثوقية في الترويسة المرسلة من قبل Cloudflare وعدم الدخول في حلقة لانهائية. أما في حال وجود بيئة واحدة فقط مثلاً production ولا يتم تطوير المشروع على بيئات مختلفة، فيمكن التحويل إلى https بتعديل ملف htaccess كالتالي: RewriteEngine On RewriteCond %{HTTPS} !on RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  20. يمكنك إضافة CSRF ضمن الفورم نفسه، وبعدها الحصول على قيمته حسب ال id: <input type="hidden" name="_token" id="token" value="{{ csrf_token() }}"> ثم في الجافاسكريبت: var data = { "_token": $('#token').val() }; وبذلك، لا داعي لأن يتواجد كود الجافاسكريبت ضمن ملف blade ويمكنك فصلهم. وأيضاً في حال وجود عدة عمليات ajax في صفحات متفرقة من ملفات المشروع، يمكنك إضافة التالي في ترويسة الصفحة الرئيسية للمشروع: <meta name="csrf-token" content="{{ csrf_token() }}" /> ثم الكود التالي: <script type="text/javascript"> $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); </script> وبعدها يمكنك إجراء AJAX بشكل عادي في باقي المكونات والصفحات، فسيتم دوماً إضافة ال CSRF لجميع العمليات بدلاً من إعادة كتابتها في كل عملية.
  21. يمكنك إضافة تابع closure ضمن الاستعلام بالشكل التالي: Post::query() ->with(array('user' => function($query) { $query->select('id','username'); })) ->get(); بحيث يتم استعادة القيم المررة ضمن select بدلاً من كامل الجدول. ووفقاً للتوثيق الرسمي يجب دوماً إضافة الحقل id وأي مفتاح ثانوي آخر موجود ضمن الجدول في هذا الإجراء لضمان الحصول على البيانات المطلوبة. وبدءً من نسخة laravel 5.5 أصبح يمكننا استخدام التالي للحصول على النتيجة نفسها: Post::with('user:id,username')->get(); أو public function user() { return $this->belongsTo('User')->select(array('id', 'username')); } وبشكل مختصر في النسخ الحديثة يمكنك استخدام التوابع السهمية: PHP 7 Post::with(['user' => fn ($query) => $query->select('id','username')])->get();
  22. إن تنفيذ ذلك بشكل أمثلي وفق التوثيق الرسمي للارافيل يتم عن طريق أحداث Eloquent Events، فيمكنك استخدام الحدث deleting وتنفيذ أي كود مرافق لعملية الحذف كالتالي: class User extends Eloquent { public function photos() { return $this->has_many('Photo'); } public static function boot() { parent::boot(); static::deleting(function($user) { $user->photos()->delete(); // تنفيذ العمليات هنا }); } } بحيث يتم استدعاء التابع قبل عملية الحذف ويتم حذف جميع البيانات المرتبطة بهذا المستخدم. من الأفضل أيضاً استخدام التناقلات transactions ووضع كامل العملية بداخلها لضمان حماية العملية وارتباط عمليات الحذف مع بعضها في حال حدوث أي خطأ. وبهذه الحالة تستطيع أيضاً في المستقبل إجراء أي تعديل على آلية الحذف دون أن يؤثر ذلك على بنية قاعدة البيانات أو الجداول والبيانات الموجودة فيها.
  23. المشكلة بسبب get فهي تعيد مجموعة من السجلات بدل من سجل واجد، ويمكنك إجراء حلقة للمرور على هذه السجلات كما تم الشرح في التعليقات. ولكن في حال كانت البيانات المراد تمريرها هي لسجل واحد (أي لا وجود لعدة سجلات) لا داعي لاستخدام الحلقات. يمكنك تغيير الاستعلام وإضافة first وعندها سيتم استعادة أول سجل ويتم قصره ليصبح سجل واحد بدلاً من مجموعة بالشكل التالي: $about = Page::where('page', 'about-me')->first();
  24. إن المشكلة هنا في إعدادات خادم الويب، فلا يجب أن تكون الملفات خارج مجلّد public مرئية أو قابلة للوصول من قبل المستخدم. في حال كان خادم الويب من نوع Apache يجب إجراء التعديلات التالية: DocumentRoot "/path_to_laravel_project/public" <Directory "/path_to_laravel_project/public"> بحيث تكون DocumentRoot و Directory موجّهة إلى مجلّد public داخل المشروع، أما في الخوادم من نوع nginx: root /path_to_laravel_project/public; وبعد هذه التعديلات جميع ملفات لارافيل خارج مجلّد public لن تكون مرئية عن طريق متصفح الويب أبداً.
  25. وفقاً للتوثيق الرسمي في لارافيل، يفضّل وضع الملفات العامة مثل الصور ضمن المجلّد public، ولكن في حال وجود الملفات في مجلّد آخر ولإتاحته على الويب يمكن إنشاء رابط يدعى symbolic من المسار public/storage إلى المسار storage/app/public كالتالي: ln -s /path/to/laravel/storage/app/public /path/to/laravel/public/storage الآن يمكنك إضافة رابط URL ضمن ال views باستخدام asset helper بالشكل التالي: echo asset('storage/file.txt'); ولكن في بعض الحالات لدى بعض الاستضافات المشتركة لا يمكنك إنشاء symbolic link عندها يمكنك إنشاء مسار جديد route في لارافيل والتوجيه إليه عند طلب الملفات. مثال: Route::get('storage/{filename}', function ($filename) { $path = storage_path('public/' . $filename); if (!File::exists($path)) { abort(404); } $file = File::get($path); $type = File::mimeType($path); $response = Response::make($file, 200); $response->header("Content-Type", $type); return $response; }); أما للصور، فيمكن عن طريق لارافيل استخدام مكتبة الصور كالتالي: Route::get('storage/{filename}', function ($filename) { return Image::make(storage_path('public/' . $filename))->response(); }); الآن يمكن ببساطة وضع الرابط التالي في أي صفحة view : http://somedomain.com/storage/image.jpg مع استبدال somedomain باسم النطاق الخاص بك.
×
×
  • أضف...