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

سمير عبود

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

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

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

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

    34

إجابات الأسئلة

  1. إجابة سمير عبود سؤال في خطأ أثناء رفع ملف في Laravel كانت الإجابة المقبولة   
    تحدث هذه المُشكلة لك بسبب أنك حددت إسم المُجلد في المُعامل الأول للدالة put، مثلاً إن كنت تريد وضع الملفات داخل مُجلد images يُمكنك ذلك من خلال:
    public function test(Request $request) { $fileInForm = 'file'; if ($request->hasFile($fileInForm)) { $file = $request->file($fileInForm); if ($file->isValid()) { // Filename is hashed filename + part of timestamp $hashedName = hash_file('md5', $file->path()); $timestamp = microtime(); $newFilename = $hashedName . $timestamp . '.' . $file->getClientOriginalExtension(); Storage::disk('local')->putFile('images', $file); } } } في هذه الحالة سيتم حفظ الملفات داخل مُجلد images و ستُعطي لارافيل إسم مُختلف للملف المرفوع في كل مرة تلقائياً، و ستُرجع الدالة putFile المسار الذي تم حفظ الملف فيه يُمكنك حفظه إن احتجت له.
    إن كنت ترغب في وضع الإسم الذي يُحفظ به الملف بنفسك يُمكنك إستخدام الدالة putFileAs بنفس الطريقة و تُمرر الإسم الذي ترغب فيه كمعامل ثالث:
    public function test(Request $request) { $fileInForm = 'file'; if ($request->hasFile($fileInForm)) { $file = $request->file($fileInForm); if ($file->isValid()) { // Filename is hashed filename + part of timestamp $hashedName = hash_file('md5', $file->path()); $timestamp = microtime(); $newFilename = $hashedName . $timestamp . '.' . $file->getClientOriginalExtension(); Storage::disk('local')->putFileAs('images', $file, $newFilename); } } } تُرجع الدالة أيضاً مسار الملف.
    تُتيح لارافيل أيضاً دالتي store و storeAs لكن هاتين الدالتين لا تُستخدمان بإستعمال الfacade بل مُباشرة على الملف بهذا الشكل مثلاً:
    $path = $request->file('file')->store('images'); $path = $request->file('file')->storeAs( 'images', $newName );  
  2. إجابة سمير عبود سؤال في قاعدة البيانات و الإختبارات في Laravel كانت الإجابة المقبولة   
    إطار العمل لارافيل مُجهز بشكل جيد للقيام بالإختبارات بشتى أنواعها يُمكنك إستخدام قاعدة بيانات ثانية للقيام بالإختبارات عليها لكن أي مشروع تقوم بإنشائه ستجده مُجهز مُسبقاً للقيام بالإختبارات على قاعدة بيانات من نوع sqlite في الذاكرة أي لست بحاجة لإنشاء قاعدة بيانات بالأساس فكما تعلم أن التعامل مع الذاكرة يكون أسرع من التعامل مع ملف في القرص الصلب لذلك تحتاج فقط للذهاب إلى ملف  phpunit.xml حيث ستجد السطرين التاليين:
    <!-- <server name="DB_CONNECTION" value="sqlite"/> --> <!-- <server name="DB_DATABASE" value=":memory:"/> --> مٌعلقين فقط قم بإزالة التعليق: 
    <server name="DB_CONNECTION" value="sqlite"/> <server name="DB_DATABASE" value=":memory:"/> لكن قبل أن تُفكر في قاعدة البيانات يجب عليك كتابة الخطوات التي تريد أن تسير عليها و تُنفذ أمر phpunit و كل مرة يظهر لك خطأ تُحاول تصليحه إلى أن تصل إلى نجاح الإختبار مثلا لنكتب إختبار خاصية إضافة كتاب:
    class BookTest extends TestCase { /** @test */ public function a_book_can_be_added_to_the_library() { } } ماهي خطوات إضافة كتاب؟ أليست كالتالي إرسال بيانات الكتاب إلى مسار مُعين ثم التأكد من أن الكتاب أضيف لقاعدة البيانات إذا لنكتب هذه الخطوات داخل التابع الذي أنشأناه:
    <?php $this->post('/books', [ 'title' => 'Book one', 'author' => 'Kamel', ]); $this->assertCount(1, Book::all()); إذا قمنا بذلك ثم نفذنا أمر phpunit سيفشل الإختبار بالطبع لكنه سيفشل في الخطوة الثانية و نحن ننتظر منه أن يفشل في الخطوة الأولى، لماذا؟ لان لارافيل إفتراضياً تقوم بمُعالجة الإستثناءات التي تُرمى لذلك يجب أن نُخبرها بأن لا تُعالج الإستثناء و بأن تقوم بعرضه و لحسن الحظ هي توفر دالة للقيام بذلك إسمها withoutExceptionHandling و دالة أخرى إسمها withExceptionHandling و هي ما يتم تنفيذه لذلك لابد من تعديلها حتى نرى فشل الإختبار:
    class BookTest extends TestCase { /** @test */ public function a_book_can_be_added_to_the_library() { $this->withoutExceptionHandling(); $this->post('/books', [ 'title' => 'Book one', 'author' => 'Kamel', ]); $this->assertCount(1, Book::all()); } } الآن لو قمنا بتنفيذ أمر phpunit  سيفشل و سيُعطينا السبب:
    NotFoundHttpException: POST http://localhost/books هذا الإستثناء يعني أن المسار الذي نُحاول الوصول له غير موجود و بالتالي نفتح ملف web.php ثم نضيف المسار:
    Route::post('/books', [BookController::class, 'store']); بعد أن أنشأنا المسار نُعيد تجربة الإختبار و في هذه المرة سيظهر الخطأ التالي:
    BindingResolutionException: Target class [BookController] does not exist. ما يعني أن المُتحكم الذي أنشأناه غير موجود.
    فلنقم بإنشائه:
    php artisan make:controller BookController ثم نقوم بإستدعائه داخل ملف web.php:
    <?php use App\Http\Controllers\BookController; بعد ذلك نُعيد تجربة الإختبار عن طريق الأمر phpunit و في هذه الحالة سيفشل الإختبار بالسبب التالي:
    BadMethodCallException: Method App\Http\Controllers\BookController::store does not exist. يعني أن التابع store غير موجود في المُتحكم BookController دعنا نضيفه:
    <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class BookController extends Controller { public function store() { } } مرة أخرى نُجرب الأمر phpunit و سيفشل الإختبار لكن في هذه المرة سيفشل في الخطوة الثانية و سيُعطي السبب التالي:
    Class 'Tests\Feature\Book' not found أي أن الصنف Book غير موجود دعنا نقوم بإضافة النموذج و ملف التهجير الخاص به و نستدعيه في كلاس الإختبار فوق:
    php artisan make:model Book -m وفي الكلاس BookTest نقوم بإستدعائه:
    use App\Models\Book; مرة أخرى نُجرب الأمر phpunit و بطبيعة الحال سيفشل أيضا و سيُعطي السبب التالي:
    QueryException: SQLSTATE[HY000]: General error: 1 no such table: books (SQL: select * from "books") هذا معناه أنه يُحاول جلب كل الكتب لكن نحن لغاية الآن لم نقم بتهجير قاعدة البيانات و نرجع لأول ما أخبرتك به أن إستعمال قاعدة بيانات ثانية من أجل الإختبارات لذلك نقوم بإلغاء التعليق من السطرين في ملف phpunit.xml، ثم نضيف ال trait الذي إسمه RefreshDatabase داخل صنف الإختبار ستجد أنه قد تم إستدعاؤه لكنه غير مستخدم دعنا نستخدمه:
    use Illuminate\Foundation\Testing\RefreshDatabase; class BookTest extends TestCase { use RefreshDatabase; } و هذا ال trait الهدف منه هو تنفيذ أمر التهجير عند تنفيذ الإختبار و عند إنتهاء الإختبار يقوم بعمل reset.
    بعد ذلك نقوم مرة أخرى بتنفيذ الأمر phpunit و بطبيعة الحال سيفشل أيضا و سيُعطي السبب التالي:
    Failed asserting that actual size 0 matches expected size 1. هذا الخطأ يعني أنه لم يتم إضافة الكتاب فهو جلب كل الكتب لكن وجد أن عددها 0 لكن نحن توقعنا 1 و هذا لأن الدالة store لا تقوم بشيء لغاية الآن، دعنا نضيف أكواد إضافة كتاب:
    use App\Models\Book; class BookController extends Controller { public function store() { Book::create([ 'title' => request('title'), 'author' => request('author') ]); } } بعد ذلك نقوم مرة أخرى بتنفيذ الأمر phpunit و بطبيعة الحال سيفشل لكن هذه المرة سيُعطي الخطأ التالي:
    MassAssignmentException: Add [title] to fillable property to allow mass assignment و هذا لأن لارافيل تُحاول حمايتك يُمكننا في هذه الحالة إخبار لارافيل أننا سنقوم بحماية أنفسنا و لا داعي أن تتدخل في هذا الأمر بعمل set للخاصية guarded في النموذج Book و جعلها  فارغة:
    class Book extends Model { use HasFactory; protected $guarded = []; } بعد ذلك نقوم مرة أخرى بتنفيذ الأمر phpunit و بطبيعة الحال سيفشل أيضاً بسبب أن ملف التهجير الخاص بالكتب لا يوجد به الأعمدة title و author:
    QueryException: SQLSTATE[HY000]: General error: 1 table books has no column named title نقوم بإضافتها في ملف التهجير:
    $table->string('title'); $table->string('author'); ثم نعيد تجربة الإختبار عن طريق الأمر phpunit و أخيراً هذه المرة سينجح الإختبار. بسبب أن خاصية إضافة كتاب تم إضافتها بنجاح.
    و هكذا تقوم بإتباع نفس الآلية في بقية الإختبارات، نحن لم نختبر ال validation و لم نختبر إعادة توجيه المُستخدم مثلاً ، يُمكنك إختبار الخصائص بنفس الطريقة
  3. إجابة سمير عبود سؤال في الإختبارات في Laravel كانت الإجابة المقبولة   
    البرمجة الموجهة بالإختبار هي البرمجة عن طريق البدء بكتابة إختبارات لكل وظيفة بالتطبيق، وكل إختبار يجب أن يقوم بتحديد وشرح الكيفية التي سيتم التعامل بها مع الكود وما هو الناتج الذي من المفترض أن يقوم بإرجاعه في حال تم تنفيذ كل شيء بنجاح، وتقوم هذه الاختبارات بإرجاع إما حالة نجاح والتي تعني أن الكود يعمل بالطريقة الصحيحة التي يجب أن يقوم بها، أو حالة فشل في حال أن الكود به أخطاء وأنه لا يقوم بإرجاع الناتج الصحيح الذي يجب أن يقوم بإرجاعه لحالة الاختبار تلك.
    لذلك إن كنت تريد إنشاء تطبيق أو مشروع يعمل بشكل جيد و مُختبر من عدة نواحي، و تنتقل بمستواك في تطوير البرمجيات إلى مُستوى أعلى فعليك النظر في هذا الموضوع.
    هذه بعض الفوائد:
    تحدد لك الطريق للبدء بكتابة الكود فعوض أن تكون متردد في كتابة خصائص التطبيق وقلق بشأن إذا ما كان الكود الذي تكتبه سيعمل بشكل صحيح فالإختبارات ستقوم بقيادتك تقليل الأخطاء في المشروع يعطيك الثقة بالنفس تسهيل عملية إعادة بناء التعليمات البرمجية أو ما يُسمى بال refactoring دون القلق على عمل الخصائص إضافة خصائص و العمل على طلبات العميل بشكل سليم و بدون أية قلق هناك بعض القواعد التي يجب أن تنتبه لها عند إنشائك لأصناف الإختبار في laravel ف phpunit تبحث عن الملفات التي تنتهي ب Test.php لذلك على كل من الملف و الكلاس أن ينتهيان ب Test. و عند إنشائك لملف Test جديد عن طريق أمر Artisan عليك أن تُحدد ذلك:
    php artisan make:test JustExampleTest أيضاً أسماء التوابع يجب أن تبدأ بالكلمة test كما يلي:
    public function test_method_to_assert_something() { $result = 2 * 5; $this->assertEquals(50, $result); } الآن إذا قمت بتنفيذ أمر phpunit سيفشل الإختبار و هو ما نتوقعه ان يحدث. وسيُعطيك النتيجة التالية:
    Failed asserting that 10 matches expected 50. إذا أردنا تسمية التوابع بأسماء أخرى غير التي تبدأ ب test يُمكننا ذلك لكن يجب أن نُحدد ال annotation لكل تابع على أنه test بهذا الشكل مثلا:
    class JustExampleTest extends TestCase { /** @test */ public function it_just_a_simple_test() { $result = 2 * 5; $this->assertEquals(50, $result); } } بعض هذه الإعدادات يُمكن تعديلها من خلال ملف phpunit.xml لكن لا داعي لذلك، فقط إحترم تسمية الملفات و ضع ال annotation.
  4. إجابة سمير عبود سؤال في حذف ملفات مجلد بإستخدام Laravel كانت الإجابة المقبولة   
    يُمكنك حذف جميع ملفات مُجلد بإستخدام التابع cleanDirectory على الواجهة: File بهذا الشكل:
    File::cleanDirectory("storage/app/public/products"); و سيُعطيك true في حالة تم الحذف أما إن كان المسار غير موجود سيُعطيك false.
    او بإمكانك إستخدام التالي أيضاً:
    use Illuminate\Filesystem\Filesystem; $fs = new Filesystem; $fs->cleanDirectory("storage/app/public/products"); أما إن أردت حذف مُجلد بكافة الملفات التي بداخله يُمكنك إستخدام التابع deleteDirectory بهذا الشكل:
    File::deleteDirectory("storage/app/public/products"); الفرق بين الطريقتين ان الأولى تحذف الملفات التي بداخل المُجلد فقط و تُبقي على المُجلد نفسه أما الثانية فتحذف المُجلد نفسه و ما بداخله.
    أما الطريقة التي تستخدمها فهي لحذف ملف واحد فقط بتمرير مساره للتابع delete كما يمكنك إستخدام نفس التابع لحذف مجموعة من الملفات بتمرير مسارات هذه الملفات في مصفوفة و بالتالي يُمكن إستخدام التابع allFiles لجلب الملفات الموجودة في مجلد ما على شكل مصفوفة و نُمررها للتابع delete بالشكل التالي:
    $files = Storage::allFiles("public/products"); Storage::delete($files); لاحظ أننا لم نمرر المسار بداية من app لأنه توابع الصنف Storage تنظر مباشرة داخل المجلد app و بالتالي إن قمت بتمريره في مسار الملف ستفترض أن هناك مجلد app داخل مُجلد app هكذا: storage/app/app
  5. إجابة سمير عبود سؤال في مشاريع للتدريب على لارافيل كانت الإجابة المقبولة   
    من بين المشاريع التي يُمكنك التدرب و تطبيق الأساسيات عليها هي مشروع بناء منتدى بسيط حيث يُمكن مبدئياً العمل على هذه الخصائص:
    في المنتدى مجموعة من الأعضاء يُمكنهم تسجيل الدخول و الخروج و الإشتراك إتاحة إنشاء مُساهمات داخل المُنتدى للأعضاء الردود على المُساهمات  تصنيفات المُساهمات فلترة المُساهمات حسب التصنيفات فلترة المُساهمات حسب الأكثر شعبية و التي لم يتم الإجابة عنها. فلترة المُساهمات حسب المستخدمين إمكانية الإعجاب بالردود الحساب الشخصي لكل عضو عرض نشاط المستخدم في المنتدى إمكانية الإشتراك بمُساهمة بحيث عندما يتم إضافة رد عليها يتم إشعار المُشتركين بذلك و العديد من الخصائص التي بإمكانك إضافتها مع الوقت 
  6. إجابة سمير عبود سؤال في منع مُستخدم من تسجيل الدخول إلى حسابه لتاريخ محدد في laravel كانت الإجابة المقبولة   
    يُمكن ذلك بإضافة حقل جديد لجدول المُستخدم banned_until و إستخدام middleware تعمل على منع المُستخدم من تسجيل الدخول إذا كان في فترة توقيف حسابه
    إضافة الحقل banned_until إلى جدول المستخدمين: php artisan make:migration add_banned_until_to_users_table هذا الأمر سيُنشئ ملف تهجير يُمكننا من إضافة حقل جديد لجدول المستخدمين.
    class AddBannedUntilToUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->timestamp('banned_until')->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('banned_until'); }); } } بعد ذلك نقوم بتنفيذ أمر التهجير:
    php artisan migrate هذا يعني أن المُستخدم إن كانت banned_until فارغة أي null فإن الحساب نشيط، اما إن كان بالحقل تاريخ مُستقبلي فإن الحساب قد تم إيقافه.
    نضيف الحقل إلى مصفوفة fillable و مصفوفة dates في النموذج User و ذلك حتى نستطيع مُعاملة الحقل على أنه تاريخ: class User extends Authenticatable { protected $fillable = [ 'name', 'email', 'password', 'banned_until' ]; protected $dates = [ 'banned_until' ]; } نقوم بإنشاء middleware نُسميها CheckBanned بهذا الأمر: php artisan make:middleware CheckBanned سيتم إنشاء الmiddleware في المسار التالي app/Http/Middleware نقوم بفتح الملف و نُعدل على الدالة handle بالشكل التالي:
    <?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Str; class CheckBanned { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle(Request $request, Closure $next) { if (auth()->check() && auth()->user()->banned_until && now()->lessThan(auth()->user()->banned_until)) { $banned_days = now()->diffInDays(auth()->user()->banned_until); auth()->logout(); $message = 'Your account has been suspended for '.$banned_days.' '.Str::plural('day', $banned_days).'. Please contact administrator.'; return redirect()->route('login')->withMessage($message); } return $next($request); } } تعمل الmiddleware على التحقق من أن المُصادقة تمت أي أن المستخدم أدخل بيانات صحيحة، و أن الحقل banned_until لهذا المُستخدم ليس فارغ و أن الحقل به تاريخ مُستقبلي: إذا تحققت هذه الشروط تقوم بحساب فارق الأيام بين التاريخ الحالي و تاريخ الإيقاف و تقوم بتسجيل خروج للمُستخدم و إعادة توجيهه إلى صفحة تسجيل الخروج مع تمرير الرسالة.
    يُمكن تمرير رسالة مُختلفة بحسب عدد الأيام كأن نتحقق إن كان عدد الأيام أقل من 20 نعرض عدد الأيام و إذا كان عدد الأيام اكبر لا نعرض عدد الأيام. فقط نقول أن الحساب تم إيقافه و لا نذكر المدة. الأمر راجع لك في هذه النقطة.
    يتبقى تسجيل هذه الmiddleware و يتم ذلك على مستوى الملف app/Http/Kernel.php في المصفوفة middlewareGroups داخل المصفوفة ذات المفتاح web: protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, // ... other middleware classes \App\Http\Middleware\CheckBanned::class, ], الآن نقوم بعرض الرسالة في حالة كانت موجودة على مستوى صفحة العرض login.blade.php: <div class="card-body"> @if (session('message')) <div class="alert alert-danger">{{ session('message') }}</div> @endif <form method="POST" action="{{ route('login') }}"> ... و هذه النتيجة:

  7. إجابة سمير عبود سؤال في حماية وصول الزوار ل route محدد في laravel كانت الإجابة المقبولة   
    يُمكن حماية المسار بإستخدام الطبقة الوسيطة أو الmiddleware المُسماة auth بهذا الشكل:
    Route::post('threads/{thread}/replies', [ReplyController::class, 'store'])->middleware('auth'); أو يُمكنك عمل ذلك في المُتحكم ReplyController لأنه سيعطيك حرية أكثر من خلال الباني:
    <?php class ReplyController extends Controller { public function __construct() { $this->middleware('auth')->only('store'); } } من خلال التابع only يُمكنك تحديد التوابع التي تريد تطبيق الmiddleware عليها.
    أما في جزء العرض فيُمكنك إستخدام توجيه مُحرك blade الذي يُكتب:
    @auth أو إستخدم شرط بسيط للتحقق من أن المُصادقة مُحققة:
    @if(auth()->check()) بهذا الشكل ككل:
    @auth <div class="row justify-content-center mt-3"> <div class="col-md-8"> <form action="{{ $thread->path . "/replies" }}" method="post"> @csrf <div class="form-group"> <textarea name="body" class="form-control" rows="5" placeholder="Have something to say?"></textarea> </div> <button type="submit" class="btn btn-secondary">Post</button> </form> </div> </div> @else <p class="text-center mt-3">Please <a href="{{ route('login') }}">sign in</a> to participate in this discussion.</p> @endauth و هكذا سيتم عرض النموذج إلا في حالة كان هناك مُستخدم مُصادق عليه أما إن كان زائر سيتم عرض رابط يُخبره بضرورة تسجيل الدخول لإضافة تعليق.
  8. إجابة سمير عبود سؤال في أكثر 5 منتجات مبيعا باستخدام Laravel كانت الإجابة المقبولة   
    بإمكانك إستعمال هذه الطريقة لجلب أكثر منتجات إشتراءاً في آخر شهر:
    <?php $most_purchased_last_month = Product::join("purchases", "purchases.product_id", "=", "products.id") ->where("purchases.created_at", ">=", date("Y-m-d H:i:s", strtotime('-1 month', time()))) // لجلب مشتريات هذا آخر شهر فقط ->groupBy("products.id") // التجميع على أساس معرف المنتج ->orderBy(DB::raw('COUNT(products.id)'), 'desc') // الترتيب على أساس عدد المشتريات لكل منتج ->take(5) // نأخذ 5 منتجات فقط كحد أعظمي ->get(array(DB::raw('COUNT(products.id) as purchases_count'), 'products.*')); // جلب كافة بيانات المنتج بالإضافة إلى عدد المشتريات لكل منتج بنفس الطريقة يُمكن التلاعب في التابع where لجلب الأكثر شراءً في آخر 7 أيام:
    <?php $most_purchased_last_week = Product::join("purchases", "purchases.product_id", "=", "products.id") ->where("purchases.created_at", ">=", date("Y-m-d H:i:s", strtotime('-7 days', time()))) // لجلب مشتريات هذا آخر 7 أيام فقط ->groupBy("products.id") // التجميع على أساس معرف المنتج ->orderBy(DB::raw('COUNT(products.id)'), 'desc') // الترتيب على أساس عدد المشتريات لكل منتج ->take(5) // نأخذ 5 منتجات فقط كحد أعظمي ->get(array(DB::raw('COUNT(products.id) as purchases_count'), 'products.*')); // جلب كافة بيانات المنتج بالإضافة إلى عدد المشتريات أما بخصوص آخر سنة أيضاً تقوم بتغيير where بهذا الشكل:
    <?php ->where("purchases.created_at", ">=", date("Y-m-d H:i:s", strtotime('-1 year', time()))) أما إن أزلت سطر التابع where كلياً فسيتم جلب أكثر 5 منتجات شراءً منذ البداية.
  9. إجابة سمير عبود سؤال في مشاركة بيانات مع layout في laravel كانت الإجابة المقبولة   
    يُمكنك عمل ذلك من خلال AppServiceProvider من خلال التابع boot:
    <?php public function boot() { view()->share('categories', Category::all()); } مع تضمين الكلاس Category في بداية الملف:
    <?php use App\Models\Category; // إستدعاء الكلاس يكون على حسب مجال الأسماء الخاص به و بهذا الشكل يُمكنك إستخدام المُتغير categories في أي صفحة عرض تريدها. لانه قد تمت مشاركته مع جميع الviews.
    لكن إذا أردت مُشاركة المُتغير categories مع صفحة عرض مُعينة مثلاً و ليس كل صفحات العرض يُمكنك ذلك من خلال AppServiceProvider من خلال التابع boot:
    <?php use App\Models\Category; public function boot() { //view()->share('categories', Category::all()); view()->composer('layouts.app', function($view) { $view->with('categories', Category::all()); }); } بهذه الطريقة أصبح المُتغير categories مُتاحا لصفحة العرض app.blade.php يُمكنك إستخدامه فيها لكن بعكس الطريقة الأولى لن تتمكن من إستخدامه في صفحات عرض أخرى لأنه متاح لهذه الصفحة فقط، اقصد لو استخدمنا المتغير لعرض الأقسام في صفحة app.blade.php ستعرض الأقسام في بقية الصفحات الأخرى التي تعتمد على هذه الصفحة كقالب، لكن لن تتمكن الصفحات الأخرى من إستخدام المُتغير بطريقة أو بأخرى لأنه لن يكون متاحاً لها فهو متاح للإستخدام فقط في الصفحة app.blade.php،
    ماذا لو أردت إتاحة هذا المُتغير لمجموعة من صفحات العرض (views) تستخدمه كيفما شاءت!!؟ يُمكنك ذلك كما يلي:
    <?php use App\Models\Category; public function boot() { //view()->share('categories', Category::all()); view()->composer(['layouts.app', 'posts.create'], function($view) { $view->with('categories', Category::all()); }); } في هذا المثال مررنا المتغير categories لكل من صفحة العرض app.blade.php الموجودة في مجلد layouts و ايضاً صفحة العرض create.blade.php الموجدة في مجلد posts سيكون المُتغير متاح لكليهما، و بهذه الطريقة يُمكنك تمرير المتغير لأي صفحة أخرى تريد.
    يمكنك الإطلاع على توثيق موسوعة حسوب الخاص بهذا الموضوع: مشاركة البيانات و مؤلّفو الواجهات
  10. إجابة سمير عبود سؤال في كيفية تخزين الإيموجي في قاعدة البيانات بشكل صحيح كانت الإجابة المقبولة   
    مرحباً محمود،
    هناك جزئين في المُشكلة التي تُواجهها جزء التخزين و جزء العرض، حتى تقوم بتخزين الرموز التعبيرية في قاعدة البيانات بالشكل الصحيح 
    تغيير ترميز قاعدة البيانات: ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;  
    تغيير الترميز لجدول البيانات: ALTER TABLE tablename CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;  
    مثال لإستعلام تخزين:
    INSERT INTO tasks (`body`, `project_id`) VALUES ('😜😀 Hdhdhdh😜😀😊😃hzhzhzzhjzj 😜😀😀😊', 2)
    عمل set للترميز الخاص بالإتصال للترميز: utf8mb4 
    <?php $con = new mysqli($server, $user, $password, $database_name); $con->set_charset('utf8mb4');  
    عرض نتيجة الإستعلام:
    <?php $stmt = $conn->prepare("SELECT * from tasks"); // prepare the query $stmt->execute(); $result = $stmt->get_result(); // get the mysqli result while($r = $result->fetch_assoc()) { echo "<p>{$r['body']}</p>"; }
    بالتوفيق.
  11. إجابة سمير عبود سؤال في ماذا افعل اذا ما لم يرد علي العميل؟ كانت الإجابة المقبولة   
    مرحباً عبد الرحمن،
    لا تقلق كثيراً فمنصة مستقل تحفظ حقوق الطرفين (صاحب المشروع و المستقل) تأكد أن مبلغ ميزانية المشروع محجوز لدى الإدارة و هي الفاصل بينكما، وارد الحدوث ان يغيب أحد الطرفين لسبب ما، بإمكانك في هذا الحال الصبر قليلاً لمدة 48 ساعة خلال هذه المدة إذا لم يتواصل معك صاحب المشروع بإمكانك فتح تذكرة من خلال مركز المساعدة و شرح المشكلة لهم و سيقومون بالتدخل لتنبيه صاحب المشروع بعد مدة محددة من تاريخ التنبيه إن لم يتواصل معك سيقومون بإستلام المشروع و إن وجدو أنك قمت بإنهائه بالشكل المطلوب سيستلمونه فلا تقلق بخصوص هذا الأمر إن قمت بإنجاز كل شيء على الشكل المطلوب فتأكد أن حقك لن يضيع، قد تأخذ هذه الإجراءات بعض الوقت لذلك عليك بالصبر قليلاً.
    بالتوفيق.
  12. إجابة سمير عبود سؤال في برنامج يعكس الاسم المدخل(كوتلن) كانت الإجابة المقبولة   
    مرحباً يحيى،
    يُمكنك إستخدام الدالة reversed الموجودة في اللغة لعمل المطلوب بهذا الشكل:
    fun main() { val sentence = "Yahia" val reversed = sentence.reversed() println("The reversed sentence is: $reversed") } و ستكون النتيجة بهذا الشكل:
    The reversed sentence is: aihaY بالتوفيق.
  13. إجابة سمير عبود سؤال في مشكلة في شراء دورات من حاسوب كانت الإجابة المقبولة   
    مرحباً @belkaditouts 
    لا تقلق فالرسالة التي تم إرسالها لك توحي أن طلبك قيد المُراجعة و سيتم إرسال كافة الخطوات اللازمة و توضيحها لك في أقرب وقت على نفس البريد الإلكتروني الذي إشتركت به، إن لم يتم ذلك يُمكنك دائماً الإستفسار عن الأمر من خلال مركز المساعدة في حسوب : https://help.hsoub.com/ ثم فتح تذكرة لمُشكلتك و سيتم الرد عليك في أقرب وقت،
    أتمنى لك التوفيق.
  14. إجابة سمير عبود سؤال في شهادة بايثون كانت الإجابة المقبولة   
    مرحباً مُحمد،
    من أشهر الشهادات في لغة python هي تلك التي تُقدمها OpenEDG Python Institute و هي خمس شهادات لمبرمجي لغة بايثون و تبدأ من شهادة مبرمج مبتدئ إلى شهادة مبرمج خبير:
    1- شهادة مبرمج بايثون مبتدئ | PCEP:
    معلومات عن الاختبار:
    رمز الإختبار PCEP-30-01. مدة الإختبار 45 دقيقة. يتألف الإختبار من 30 سؤال. نوع الأسئلة هو إختيار من متعدد. نسبة النجاح 70%. الإختبار باللغة الإختبار باللغة الإنجليزية. سعر الاختبار 59$. يتمحور الإختبار حول المفاهيم الأساسية في البرمجة بلغة البايثون. لمزيد من المعلومات يُمكنك زيارة هذا : الرابط
    2- شهادة مشارك معتمد في لغة بايثون | PCAP:
    معلومات عن الاختبار:
    رمز الإختبار PCAP-31-02. مدة الإختبار 65 دقيقة. يتألف الإختبار من 40 سؤال. نوع الأسئلة هو إختيار من متعدد. نسبة النجاح 70%. الإختبار باللغة الإختبار باللغة الإنجليزية. سعر الإختبار 295$. يتمحور الإختبار حول أساسيات اللغة بالإضافة إلى بعض المفاهيم المتقدمة كالإستثناءات و التعامل مع المكتبات بالإضافة إلى مفاهيم البرمجة الكائنية بلغة بايثون،  لمزيد من المعلومات يُمكنك زيارة هذا : الرابط
    3- شهادة مبرمج بايثون محترف 1 | PCPP:
    معلومات عن الإختبار:
    رمز الإختبار PCPP-32-201. مدة الإختبار 65 دقيقة. يتألف الإختبار من 40 سؤال. نوع الأسئلة هو إختيار من متعدد. نسبة النجاح 70%. الإختبار باللغة الإنجليزية. سعر الإختبار 195$. يتمحور الإختبار حول البرمجة الكائنية بالإضافة إلى التعامل مع الملفات و المكتبات و قواعد البيانات و برمجة الواجهات الرسومية، لمزيد من المعلومات يُمكنك زيارة هذا : الرابط
    4– شهادة مبرمج بايثون محترف 2 | PCPP:
    معلومات عن الإختبار:
    رمز الإختبار PCPP-32-201. مدة الإختبار 65 دقيقة. يتألف الإختبار من 40 سؤال. نوع الأسئلة هو إختيار من متعدد. نسبة النجاح 70%. الإختبار باللغة الإنجليزية. سعر الإختبار 195$. يتمحور الإختبار حول تثبيت و إنشاء المكتبات بالإضافة إلى أنماط التصميم و أساسيات التعامل مع قواعد بيانات MySql بلغة بايثون، لمزيد من المعلومات يُمكنك زيارة هذا : الرابط
    5– مبرمج و خبير بايثون | CEPP:
    سوف تمنح هذه الشهادة بدون إجراء أي اختبار وذلك لأنك اجتزت جميع الاختبارات وحصلت على كافة الشهادات السابقة.
    لا أدري إن كانت هناك شهادات مجانية لكن يُمكن البحث عن مبادرة مليون مبرمج عربي فَلَرُبما تجد مسار يُناسبك. نصيحة مني لا تبحث عن الشهادات و إنما ابحث عن إكتساب الخبرة و تعلم ما يفيدك لبناء معرض أعمال و سيرة ذاتية قوية.
    بالتوفيق.
  15. إجابة سمير عبود سؤال في يحدث bug عند استخدام php, ajax كانت الإجابة المقبولة   
    مرحباً محمود،
    أظن أنك تستخدم PDO، بما أنك تريد الإستعلام عن عدد السجلات التي تم تخزينها في اليوم الحالي فلم لا تستخدم الدالة count التابعة للغة sql بالشكل التالي:
    <?php $checkLog = $conn->prepare("SELECT count(id) FROM logs WHERE DATE(date) = CURDATE() AND user = ?"); // prepare the query $checkLog->execute([$SUI]); $rowCount = $checkLog->fetchColumn(); // جلب عدد الصفوف // عمل الشرط المناسب حسب عدد الصفوف if($rowCount < 5) { echo "Still Yes"; }else{ echo "done today"; } المفروض إذا كان عدد الصفوف أصغر من 5 يتحقق الشرط و بالتالي يطبع عبارة still yes لكن إن كان أكبر من أو يُساوي 5 يطبع done today،
    بالتوفيق.
  16. إجابة سمير عبود سؤال في ما معنى أن العرض مستبعد  كانت الإجابة المقبولة   
    مرحباً عبد الله،
    معنى العرض المُستبعد هو أن المشروع الذي قدمت عليه هذا العرض تم توظيف مُستقل آخر عليه، بطبيعة الحال عند نشر مشروع جديد من عميل فإن مجموعة من العروض يتم تقديمها على هذا المشروع و في الأخير يتم توظيف شخص واحد وهو المُستقل الذي تم قبول عرضه، بقية العروض تُصبح تلقائياً مُستبعدة، هناك فترة مُحددة إن لم يتم فيها قبول أي عرض من طرف صاحب المشروع يتم إغلاق المشروع تلقائياً و يُمكن فتحه مرة ثانية من قبل العميل.
    مايؤثر عليك كمُستقل هو التقييمات التي تتلقاها ( التقييم الكلي بالإضافة إلى التقييمات التفصيلية) و أيضاً مُعدل إكمالك للمشاريع (كل ماكان كبير كل ما كان أحسن) إضافة إلى الأوسمة التي تتلقاها من المنصة ( مُستقل مُلتزم، مُستقل مُميز .. )
    هل تعلم ما معنى أن العروض المُستبعدة 100% معناه أن كل العروض التي قدمتها استبعدت، و في هذه الحالة لن يحدث شيء ما دام أنك تستطيع التقديم على مشاريع.
    هناك 5 حالات للعروض الخاصة بك:
    بانتظار الموافقة: مشاريع قدمت عليها و لم يتم توظيف اي مستقل عليها و لم يتم إغلاقها. قيد التنفيذ: التي قُبلت فيها و تعمل عليها و لم تُنهيها. المكتملة: عملت عليها و أكملتها المستبعدة: التي قدمت عليها و تم توظيف مستقلين غيرك ليعملو عليها. مغلقة: تم إغلاقها لتجاوز الفترة المُحددة و عدم توظيف أي مُستقل عليها. ولكل حالة نسبة من العدد الإجمالي للعروض التي قدمتها ككل.
    بالتوفيق.
     
  17. إجابة سمير عبود سؤال في مشكلة في اعداد Prepared statements كانت الإجابة المقبولة   
    مرحباً مروان،
    السبب أن المتغير result عبارة عن كائن و عندما تقوم بفحص المتغير في الشرط:
    <?php if($result){ // code } فإن الشرط مُحقق في كل الأحوال.
    الحل هناك عدة طرق من بينها:
    <?php // here prev code $stmt = $conn->prepare("SELECT * from users where name = ?"); // prepare the query $stmt->bind_param('s', $name); $stmt->execute(); $result = $stmt->get_result(); // get the mysqli result if ($result->num_rows > 0) { echo "success"; } else { die("Invalid Username or Password Please Try Again"); } او 
    <?php // prev code $stmt = $conn->prepare("SELECT * from users where name = ?"); // prepare the query $stmt->bind_param('s', $name); $stmt->execute(); if ($stmt->fetch()) { echo "success"; } else { die("Invalid Username or Password Please Try Again"); } فالخطأ كله في الشرط.
    بالتوفيق.
  18. إجابة سمير عبود سؤال في برنامج لتشغيل أكواد بلغة سي C كانت الإجابة المقبولة   
    مرحباً أحمد، 
    لم أفهم سؤالك جيدا إذا كنت تريد برنامج تكتب عليه برامج بلغة c أو لغة c++ بإمكانك إستخدام برنامج Code Blocks ما تحتاج إلى فهمه أن لغة سي تحتاج إلى برنامج ثاني إسمه مترجم (compiler) و مهمته هي تحويل الشيفرات من لغة سي إلى لغة آلة لتنفيذها و من أشهرها : 
    GCC Visual ++c على العموم بإمكانك تنصيب محرر نصوص أو أكواد ثم تنصيب المترجم لوحده لكن برنامج code Blocks يوفر الإثنين و هو عبارة عن بيئة عمل متكاملة مفتوحة المصدر، ويتم إستخدام المترجم GCC من خلال المشروع MinGW لترجمة أكواد السي، ويعتبر خيار جيد للبرمجة بلغة الس ويمكنك تحميل الحزمة البرمجية الخاصة بـ Code Blocks من خلال الموقع الخاص به ثم تختار نظام التشغيل الذي تستخدمه حاليا، وتختار الإصدار الذي ينتهي بـ mingw-setup، وهو الإصدار الذي يحتوي على المترجم GCC.
    بالتوفيق.
  19. إجابة سمير عبود سؤال في تعليمة switch في لغة JavaScript كانت الإجابة المقبولة   
    مرحباً بك،
    في الحقيقة تعليمة switch تعمل بشكل صحيح و ذلك لأن أي قيمة يتم إرجاعها في المتغير num عبارة عن سلسلة نصية (string) و بالتالي لم تُطابق أي حالة من الحالات الموجودة (cases) في تعليمة switch. إضافة إلى ذلك لا توجد تعليمة default فإذا لم تتحقق أي حالة من الحالات سيتم تنفيذها:
    default: message.innerHTML = "anything"; break; بإمكانك تحويل النوع من string إلى int بحيث مثلا: حالياً إذا أدخل المُستخدم 2 فإن القيمة التي ستُخزن في المُتغير num ستكون "2" لكن يُمكننا تحويلها إلى 2 عن طريق إستخدام الدالة parseInt كما هو موضح أدناه:
    var num = parseInt(document.getElementById("number").value); ليُصبح الكود في النهاية بهذا الشكل:
    function f1() { "use strict"; var num = parseInt(document.getElementById("number").value); var result = num * 600; var message = document.getElementById("m"); switch (num) { case 1 : message.innerHTML = "1/1/2020"; break; case 2 : message.innerHTML = "2/2/2020"; break; case 3 : message.innerHTML = "3/3/2020"; break; case 4 : message.innerHTML = "4/4/2020"; break; case 5 : message.innerHTML = "5/5/2020"; break; default: message.innerHTML = "anything"; break; } } بالتوفيق.
  20. إجابة سمير عبود سؤال في لدي مشكلة في سحب المال لpay pal كانت الإجابة المقبولة   
    و عليكم السلام و رحمة الله و بركاته،
    أظن أن المُشكلة التي تُواجهها متعلقة بحساب البايبال يُمكنك مراسلة الدعم الفني في بايبال لمعالجتها لأنه قد تحدث بعض الأمور تجعل النظام الخاص بِبايبال يَحُد من بعض خصائص الحساب إلى حين التأكد ، فقط قم بمُراسلة الدعم الفني لبايبال و اشرح لهم المُشكلة و سيقومون بتنشيط حسابك قد حدثت لي مُشكلة مشابهة و عندما راسلت الدعم الفني لمُستقل أخبروني أن المُشكلة ليست من طرفهم بل من طرف بايبال و عندما راسلت بايبال قالو انهم عاينو الحساب الخاص بي و قد صار الحساب بإمكانه الإرسال و الإستقبال بشكل عادي و عندما حاولت الإرسال مُجددا تم الإرسال بشكل طبيعي، لذلك حاول التواصل مع الطرفين و ستُحل المُشكلة في أقرب وقت.
    بالتوفيق.
  21. إجابة سمير عبود سؤال في الجمع بين عدد و كلمة Concatenation ? كانت الإجابة المقبولة   
    مرحباً @Taha NEKHLI 
    عملية الConcatenation  تُستخدم بين السلاسل النصية (strings) لذلك إن أردت جمع متغير نصي مع متغير عددي سيُعطي خطأ و لتجاوز هذا الخطأ نقوم بتحويل قيمة المتغير العددي إلى قيمة نصية و ذلك بإستخدام الدالة str بهذا الشكل:
    a = 15 b = "Taha" print(str(a) + b) # output: 15Taha الدالة input التي تستخدمها تُستعمل لقراءة ما يقوم المُستخدم بإدخاله من خلال لوحة المفاتيح و تستقبل المدخلات على هيئة سلسلة نصية مثلاً إذا أردنا طباعة رسالة للمستخدم تُفيد بإدخال عُمره و رسالة أُخرى تُفيد بإدخال إسمه ثم نطبع له رسالة تضم الإسم و العمر معاً سيكون البرنامج بالشكل التالي:
    a = input("Enter age: ") b = input("Enter Name: ") print("Hello " + b + ", Your age is: " + a) سيكون الناتج بهذا الشكل:

    بالتوفيق.
  22. إجابة سمير عبود سؤال في خطأ في كود C++ كانت الإجابة المقبولة   
    مرحباً بك،
    عندما بحثت عن الأمر وجدت أنه متعلق بإصدار c++ المُستخدم في جهازك بالإضافة إلى الcompiler فالإصدار أقل من 11 سيُسبب لك بعض الأخطاء في حين إذا كان 11 أو أكثر لن تحدث لك أي أخطاء وسيشتغل البرنامج بشكل جيد،
    إذا اردت تشغيل البرنامج على جهازك بالإصدار الموجود حالياً بإمكانك عمل بعض التغييرات على كل من الميثود Print التي تكتب في الملف بالشكل التالي:
    void Print(string file) { ofstream f; f.open (file.c_str()); // تغيير هذا السطر f << "The Name is : " << name << endl; f << "Total is : " << Total << endl; f << "TVs: " << endl; for(int i=0;i<2;i++){ f << "TVs[" << i << "] = (Number = " << TVs[i].getNo() << ", Price = " << TVs[i].getPrice() << ")" << endl; } f.close(); } بالإضافة إلى أن الدالة to_string لن تعمل على الإصدار أيضا فيجب تغيير الطريقة إلى شكل آخر و هذه الدالة main:
    int main() { Invoice* x[2]; //customer y; for(int i=0; i<2;i++){ char name[20]; char filename[20]; sprintf(name, "Invoice %d", i); x[i] = new Invoice(name); sprintf(filename, "output%d.txt", i); x[i]->Print(filename); x[i]->getMin(); cout<<"********************************"<<endl; } return 0; } و هذا الكود ككل:
    #include <iostream> #include <fstream> using namespace std; /*---------------------------------------------------*/ class Customer{ protected: string name; public: Customer(string name = "Unknown"){ this->name = name; } string getName(){ return name; } void setName(string name = "Unknown"){ this->name = name; } }; /*---------------------------------------------------*/ class TV{ private: int no; public: float price; TV(){ cout << "The TV Number is : " << endl; cin >> no; cout << "The TV Price is : " << endl; cin >> price; } float getPrice(){ return price; } int getNo(){ return no; } void setPrice(float p){ price = p; } }; /*---------------------------------------------------*/ class Invoice : protected Customer{ private: float Total = 0; public: TV TVs[2]; void ReadPrice(){ for(int i=0;i<2;i++){ cout << "TVs[" << i << "] = (Number = " << TVs[i].getNo() << ", Price = " << TVs[i].getPrice() << ")" << endl; } }; int getTotal(){ return Total; } Invoice(string name) : Customer(name){ for(int i=0;i<2;i++){ Total += TVs[i].price; } } void Print(){ cout << "The Name is : " << name << endl; cout << "Total is : " << Total << endl; cout << "TVs: " << endl; this->ReadPrice(); } void Print(string file) { ofstream f; f.open (file.c_str()); f << "The Name is : " << name << endl; f << "Total is : " << Total << endl; f << "TVs: " << endl; for(int i=0;i<2;i++){ f << "TVs[" << i << "] = (Number = " << TVs[i].getNo() << ", Price = " << TVs[i].getPrice() << ")" << endl; } f.close(); } int getMin(){ float min; min = TVs[0].price; for(int i=0 ;i < 2; i++){ if (TVs[i].price < min) min = TVs[i].price; } cout<<"The minimum :" << min <<endl; return min; } }; /*---------------------------------------------------*/ int main() { Invoice* x[2]; //customer y; for(int i=0; i<2;i++){ char name[20]; char filename[20]; sprintf(name, "Invoice %d", i); x[i] = new Invoice(name); sprintf(filename, "output%d.txt", i); x[i]->Print(filename); x[i]->getMin(); cout<<"********************************"<<endl; } return 0; } جربت كلتا الطريقتين على جهازي و اشتغل بشكل جيد، إذا لم ينجح معك بإمكانك تحديث إصدار c++ بالإضافة إلى الcompiler إلى آخر نُسخة بإمكانك إستخدام برنامج code blocks و تحميل الملف الذي يأتي معه compiler ثم تنصيبه على جهازك.
    بالتوفيق.
  23. إجابة سمير عبود سؤال في JavaScript و كيفية تعاملها مع شجرة الDOM كانت الإجابة المقبولة   
    مرحباً @Mari Carmen 
    هنا يطلب منك تغيير النص الموجود في الوسم h1 في حالة ملأ حقل الإدخال و الضغط على زر insert header
    هنا يطلب منك تغيير لون الخلفية للصفحة في حالة تحديد لون و الضغط على زر Apply
    إذا ضغط المُستخدم على أي فقرة يتغير لون خلفيتها إلى الأصفر.
    إذا ضغط المُستخدم مرتين على اي فقرة يتم إخفاؤها.
    إذا ضغط المُستخدم على زر show all paragraphs يتم إظهار كافة الفقرات في الصفحة.
    و هذه الإجابة على كل الأسئلة بالتفصيل:
    document.addEventListener("DOMContentLoaded", function() { // الإنتظار لحين تحميل كافة عناصر الصفحة let header = document.querySelector('h1'), // أول عنصر يحمل الوسم h1 allParagraph = document.querySelectorAll("p"), // جلب كافة الفقرات colorInput = document.querySelector("input[type=color]"); /* الإجابة على السؤال الأول تحديد كافة العناصر input التي تحمل القيمة Insert header و من أجل كل عنصر نضيف مستمع لحدث الضغط نجلب حقل الإدخال السابق للزر الذي تم الضغط عليه و نُعاين عدد محارف النص المًدخل إذا كان أكبر من 5 نُغير نص الوسم h1 و في الأخير نُفرغ الحقل. */ document.querySelectorAll("input[value='Insert header']").forEach(elm => { elm.addEventListener('click', function() { let headerInput = this.previousElementSibling; if (headerInput.value.length > 5) { // إذا كان عدد محارف النص المدخل أكبر من 5 header.innerText = headerInput.value; // نقوم بتغيير النص لعنوان الصفحة headerInput.value = ''; // إفراغ حقل الإدخل. } }) }); /* الإجابة على السؤال الثاني تحديد زر تغيير لون الخلفية إضافة مُستمع لحدث الضغط تغيير لون الخلفية للون الذي تم تحديده في حقل اللون */ document.querySelector("input[value='Apply to background']").addEventListener('click', function () {// إضافة مُستمع لحدث النقر على زر تغيير لون الخلفية document.body.style.backgroundColor = colorInput.value; //تغيير لون الخلفية }); /* الإجابة على السؤال الثالث عمل حلقة على كل عناصر الفقرة من أجل كل فقرة نضيق مُستمع لحدث الضغط تغيير لون خلفية الفقرة التي تم الضغط عليها إلى الأصفر تغيير لون خلفية الفقرات الأشقاء للون الأبيض */ allParagraph.forEach( p => { p.addEventListener('click', function () { this.style.backgroundColor = "yellow"; // تغيير لون خلفية الفقرة التي تم الضغط عليها // جعل لون خلفية بقية الفقرات أبيض allParagraph.forEach(item => { if (item != p) item.style.backgroundColor = "white"; }) }) }); /* الإجابة على السؤال الرابع عمل حلقة على كل عناصر الفقرة من أجل كل فقرة نضيق مُستمع لحدث الضغط المُزدوج إخفاء الفقرة المعنية */ allParagraph.forEach( p => { p.addEventListener('dblclick', function () { this.style.display = 'none'; // إخفاء الفقرة التي تم الضغط عليها مرتين }) }); /* الإجابة على السؤال الخامس تحديد زر إظهار الفقرات إضافة مُستمع لحدث الضغط عمل حلقة على كل فقرات الصفحة إظهار كل فقرة */ document.querySelector("input[value='Show paragraphs']").addEventListener('click', function () { allParagraph.forEach( p => { p.style.display = 'block'; }) }); }); بإمكانك تجربة الشيفرات من خلال موقع codepen من: هنا
    بالتوفيق.
  24. إجابة سمير عبود سؤال في ما هو SLA و SLos و paging alert كانت الإجابة المقبولة   
    مرحباً بك،
    SLA و هو إختصار ل (Service Level Agreement) أو عقد مُستوى الخدمة هو إتفاق بين طرفين أحدهما يكون مزود خدمة والآخر يكون العميل أو المستفيد من هذه الخدمة، بموجبه يتفق الطرفان على مستوى الخدمة المقدمة ويختلف عقد مستوى الخدمة عن عقد الخدمات، فهو لا يعني مجرد الاتفاق على تقديم خدمة بل أن موضوعه الأساسي هو مستوى أداء هذه الخدمة و سرعتها و جودتها. يتضمن العقد أيضاً التعويضات والجزاءات التي تترتب على الإخلال أو التقصير في أداء الخدمة. SLOs  و هو إختصار ل (Service-level objective) و هو عنصر أساسي في اتفاقية مستوى الخدمة (SLA) بين مقدم الخدمة والعميل. يتم الاتفاق على SLO كوسيلة لقياس أداء مزود الخدمة ويتم تحديدها كطريقة لتجنب النزاعات بين الطرفين على أساس سوء الفهم. SLOs هي خصائص محددة قابلة للقياس لاتفاقية مستوى الخدمة مثل التوافر أو الإنتاجية أو التردد أو وقت الاستجابة أو الجودة. تهدف SLOs  إلى تحديد الخدمة المتوقعة بين المزود والعميل وتختلف اعتمادًا على إلحاح الخدمة والموارد والميزانية. توفر SLOs وسيلة كمية لتحديد مستوى الخدمة التي يمكن أن يتوقعها العميل من الموفر. paging: في أنظمة تشغيل الحاسب هو مخطط لإدارة ذاكرة الحاسب، حيث يقوم الحاسب بتخزين البيانات واسترجاعها من وحدة التخزين الثانوية لاستخدامها في الذاكرة الرئيسية. في هذا المخطط، يسترجع نظام التشغيل البيانات من وحدة التخزين الثانوية في كتل من نفس الحجم تسمى الصفحات. يعد التصحيف جزءًا مهمًا من عمليات تشغيل الذاكرة الافتراضية في أنظمة التشغيل الحديثة، وذلك باستخدام وحدة التخزين الثانوية للسماح للبرامج بتجاوز حجم الذاكرة الفعلية المتوفرة. للتبسيط، الذاكرة الرئيسية تسمى "ذاكرة عشوائية" ووحدة التخزين الثانوية تسمى "القرص الصلب". و paging alert هو إنذار أو تنبيه يتعامل به نظام التصحيف  a pull model and push model هما الاستراتيجيتان الترويجيتان المطبقتان لإيصال المنتج إلى السوق المستهدفة فعند تواجد استراتيجية الدفع تتمثل الفكرة في دفع منتج الشركة إلى العملاء من خلال توعيتهم بذلك عند الشراء ، وتعتمد استراتيجية الجذب على فكرة كيفية الحصول على العملاء وجعلهم ينجذبون للمنتج ، وتختلف كل من استراتيجية الدفع والجذب في الطريقة التي يتم بها التعامل مع المستهلكين . فالدفع هو تلك الاستراتيجية التي تستخدم فيها كل خبرات التسويق لدفع المنتج أو الخدمة إلى سوق المبيعات ، وهو ما يؤدي إلى رواج  حركة المنتجات ، والخدمات ، والمعلومات ونقلها من خلال الوسطاء إلى المستهلك النهائي ، وفي هذه الاستراتيجية ، تقوم الشركة بتقديم منتجاتها إلى العملاء  الذين ليسوا على علم بها ، ولا يسعون إليها. في حين أن الجذب يطلق على استراتيجية العمل التي تهدف إلى توليد الاهتمام ، أو الطلب على منتج معين ، أو خدمة معينة للجمهور المستهدف بطريقة ما.
    بالتوفيق.
  25. إجابة سمير عبود سؤال في هل تخصص هندسة البرمجيات بعد خمس سنوات راح يقل الطلب عليه كانت الإجابة المقبولة   
    مرحباً بك،
    لا أحد يستطيع الإجابة على هذا السؤال لأنه لا أحد يعلم الغيب أو يستطيع التكهن لما سيحدث بعد 5 سنوات، إختر تخصصك حسب رغبتك و حسب ميولك الشخصي لأنه إذا أحببت مجالك ستُبدع فيه، لو سألت هل تخصص هندسة البرمجيات مطلوب الآن أجيبك نعم هو مطلوب فهناك العديد من الشركات التي تبحث عن موظفين في هذا المجال و هناك العديد من الشركات الناشئة التي تأسست في هذا المجال، لذلك إن كنت مُهندس برمجيات مُحترف في مجالك فالشركات هي التي ستبحث عنك ولو كنت شخص لديك خبرة كبيرة في المجال فعملك و خبرتك هي التي ستُسوق لك و تجعلك أنت من يختار مكان عملك لذلك فالأفضل لك إن كنت قد اخترت هذا المجال ان تٌركز على إكتساب أكبر قدر من الخبرة و المهارات المطلوبة في مجالك أما إن كنت تريد إختيار هذا المجال فعليك إختياره برغبة و لأنك تُحبه.
    ليس كل الناس تذهب لهذا التخصص و ليس كل من يختار هذا التخصص يُصبح مؤهل فالشركات لم تعد تهتم للمُسمى بقدر إهتمامها بما يملكه الشخص من مهارات و ما الذي سيُضيفه لها و ما الذي ستستفيد منه.
    أتمنى لك التوفيق.
×
×
  • أضف...