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

سمير عبود

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

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

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

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

    34

كل منشورات العضو سمير عبود

  1. لجلب سجلات مُحددة عن طريق id النموذج مثلاً 1، 4، و 9 نقوم بإستعمال التابع find على الmodel و تمرير مصفوفة تضم المُعرفات التي نريد جلب سجلاتها: Model::find([1, 4, 9]); أي أننا إن أردنا جلب المُستخدم الأول و الثاني يُمكننا إستخدام: User::find([1, 2]); أما إن كنا نريد جلب سجلين عشوائيين يُمكن إستخدام هذه الطريق: Model::inRandomOrder()->limit(2)->get(); الفرق بين first و get أن first يجلب أول سجل يُطابق الإستعلام، أما get تجلب كل السجلات التي تُطابق الإستعلام على شكل collection، مجموعة سجلات
  2. إذا كنت تريد وضع خاصية الإتصال بقاعدة البيانات في الصنف Teacher فطريقة فهمك للبرمجة الكائنية خاطئة، إسأل نفسك هل الأستاذ لديه خاصية إسمها إتصال بقاعدة بيانات لا فهذا غير منطقي، يُمكن أن يكون للأستاذ إسم و لقب يُمكن أن يكون له سنوات خبرة كم، راتبه هذه الأشياء المُتعلقة بالأستاذ يُمكن وضعها في الصنف الخاص به، أما ما تُحاول القيام به فهو غير منطقي، الصواب هو أن تقوم ببناء كلاس يتعلق بقاعدة البيانات و تضع الأشياء المُتعلقة بقاعدة البيانات فيه مثلا كلاس إسمه Database
  3. يُمكن حماية المسار بإستخدام الطبقة الوسيطة أو ال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 و هكذا سيتم عرض النموذج إلا في حالة كان هناك مُستخدم مُصادق عليه أما إن كان زائر سيتم عرض رابط يُخبره بضرورة تسجيل الدخول لإضافة تعليق.
  4. لا نقوم ببذر الصور و إنما أسماء هذه الصور أو المسار الخاص بها بعد رفعها في التطبيق. على سبيل المثال نريد بذر مجموعة من المُستخدمين 5 حيث لكل مُستخدم صورة و ملف التهجير الخاص بالمُستخدمين يحتوي على حقل صورة بهذا الشكل: <?php $table->string('image')->default('default.jpg'); نقوم برفع الصور إلى ملف public و نضعها في مُجلد images و لتكن الصور بالأسماء التالية مثلاً 1.png 2.png 3.png 4.png 5.png لدينا factory خاص بالنموذج User لإنشاء مُستخدم. و قمنا أيضاً بإنشاء Seeder خاص بالمستخدمين في ملف البذر نقوم بالتالي: <?php public function run() { $images = array( '1.png', '2.png', '3.png', '4.png', '5.png' ); foreach($images as $image) { User::factory()->create(['image' => $image]); } } عند تنفيذ أمر البذر سيتم إنشاء 5 مُستخدمين و لكل مُستخدم صورة من الصور التي رفعناها في المُجلد images. حيث للمُستخدم الأول بيانات عشوائية يتم تمريرها عن طريق الfactory أما في الحقل image فسيتم تخزين إسم الصورة png.1 و هكذا بالنسبة لبقية المٌستخدمين. أظن أن طريقة إستخدام الfactories في الإصدار السابع مُختلفة عن الإصدار الثامن لذلك بدل كتابة: User::factory()->create(['image' => $image]); نكتب: factory(App\User::class)->create(['image' => $image]); يعني ملف بذر المُستخدمين يُصبح كالآتي: <?php public function run() { $images = array( '1.png', '2.png', '3.png', '4.png', '5.png' ); foreach($images as $image) { factory(App\User::class)->create(['image' => $image]); } } و بالتالي الآن عند عرض صورة المُستخدم يُمكننا إستخدام <img src="{{asset('images/'. $user->image)}}" alt="user image"> أو <img src="{{asset('images/'. auth()->user()->image)}}" alt="user image">
  5. يُمكن جلب المُستخدم عن طريق تحديد مُعرف المُستخدم بهذا الشكل مثلاً: <?php $user = User::find(1); // جلب المُستخدم عن طريق تحديد المُعرف 1 // او يُمكننا إستخدام التابع where $user = User::where('id', 1)->get(); لكن السؤال المطروح عن جلب آخر مُستخدم مُسجل في التطبيق في هذه الحالة لا ندري ماهي قيمة مُعرف هذا المُستخدم لذلك نلجأ لتلك الطريقة أننا نرتب المُستخدمين حسب وقت إنشائهم من الأحدث إلى الأقدم ثم نجلب أول سجل عن طريق إستعلام واحد فقط ، يُمكن بنفس الطريقة ترتيبهم حسب المُعرف من الأكبر إلى الأصغر و جلب أول سجل أما السؤال الثاني فعن جلب سجل عشوائي من جدول ما نحن لا نعرف مُسبقاً مُعرف هذا السجل لذلك نستخدم التابع inRandomOrder ليُرتب السجلات ترتيباً عشوائياً في كل مرة يتم تنفيذه و عن طريق التابع first نجلب أول سجل بعد الترتيب العشوائي.
  6. تُعتبر العلاقات المُتعددة الأشكال من المواضيع المُتقدمة في الإطار، و العديد من المطورين يجهلون إستخدامها، بسبب أنها معقدة قليلاً، يُمكنك عدم إستخدامها لكن توجد بعض الحالات إذا ما استخدمت فيها هذا النوع من العلاقات ستُسهل عليك الكثير من الأمور، لنفترض أنك تعمل على مشروع، و هذا المشروع به مودل إسمه User و مودل ثاني إسمه Post و مودل ثالث إسمه Photo حيث أن لكل User صورة و لكل مقال صورة، و يمكن أيضاً إضافة نماذج أخرى لها علاقة مع النموذج Photo. قد يكون Product او أي كان. لنتوقف على User و Post بالإضافة إلى Photo فقط. في هذه الحالة كيف ستعمل؟ هل ستقوم بإنشاء نموذج PostPhoto لصور المقالات و جدول خاص به و نموذج ثاني UserPhoto لصور المستخدمين و جدول خاص به أيضاً، و إذا كان هناك نماذج أخرى تتعلق بالصور تُنشئ لها جداول أخرى في قاعدة البيانات أيضاً، ألا ترى أن هذه الطريقة ليست عملية! إذاً ما الحل؟ هل ستستخدم جدول واحد للصور photos و تضع فيه حقلين post_id و user_id و تجعلهما nullable ثم إن كانت الصورة تتعلق ب Post تضع مُعرف المقال في الحقل post_id و تترك الآخر null أما إن كانت الصورة تتعلق ب User تعكس الأمر. ماذا إن كان نموذج آخر يتعلق بالصور و ليكن Product هل ستضيف حقل آخر product_id لجدول الصور!! ألا تُلاحظ أن هذه الطريقة ليست عملية لأننا نضيف كل مرة حقل جديد، و كل مازادت الحقول التي ليس لها داع، تنفيذ الإستعلامات سيكون بطيء، و بالتالي فإن الأفضل هو إستخدام جدول واحد و حقلين فقط بغض النظر عن الحقول الإضافية للنموذج فنحن نتحدث عن حقول العلاقات. و هذين الحقلين هما: imageable_id سيتم فيه تخزين مُعرف النموذج سواء كان User او Post او اي كان imageable_type و فيه سيتم تخزين نوع النموذج مثلا Post او User على شكل سلسلة نصية و بهذه الطريقة تمكنا من إستخدام جدول واحد و تخلصنا من الحقول الإضافية، أيضاً إذا أردنا مستقبلاً إضافة نموذج ثالث له علاقة مع نموذج الصور لسنا بحاجة للتعديل على هيكلية جدول الصور. ملفات التهجير ستكون بهذا الشكل: جدول photos: <?php class CreatePhotosTable extends Migration { public function up() { Schema::create('photos', function (Blueprint $table) { $table->id(); $table->unsignedInteger('imageable_id'); $table->string('imageable_type'); // other fields $table->timestamps(); }); } // ... } العلاقات: النموذج Photo: <?php class Photo extends Model { // ... public function imageable() { return $this->morphTo(); } } النموذج User: <?php class User extends Model { // ... public function photo() { return $this->morphOne(Photo::class, 'imageable'); } } النموذج Post: <?php class Post extends Model { // ... public function photo() { return $this->morphOne(Photo::class, 'imageable'); } } هذه العلاقة تُسمى ( one to one polymorphic) أي واحد لواحد مُتعدد الأشكال يعني لكل مُستخدم صورة و لكل مقال صورة و لكل منتج صورة. ماذا لو كان لدينا الحالة التالية لكل مستخدم عدة صور و لكل مقال عدة صور هذه العلاقة تُسمى One To Many (Polymorphic) هي تُشبه العلاقة الأولى فعند تطبيقها نحتاج فقط لتعديل إسم العلاقة من photo إلى photos حتى تُصبح مُعبرة و نُغير التابع morphOne إلى morphMany بهذا الشكل في كل من النموذج User و النموذج Post: <?php public function photos() { return $this->morphMany(Photo::class, 'imageable'); } ماذا لو أردنا أن تكون صورة ما مُتعلقة بكل من النموذج User و النموذج Post، يعني صورة تابعة لمجموعة من المستخدمين و تابعة في نفس الوقت لمجموعة من المقالات، هذه العلاقة تُسمى Many To Many (Polymorphic) في هذه الحالة نحتاج إلى جدول آخر يُسمى Pivot Table يحتوي على التالي: imageables photo_id - integer imageable_id - integer imageable_type - string بحيث photo_id يُشير إلى معرف الصورة في جدول الصور الذي يكون بالشكل التالي: photos id - integer -- other fields حيث أن العلاقات ستكون بالشكل التالي: النموذج Post و النموذج User: <?php public function photos() { return $this->morphToMany(Photo::class, 'imageable'); } و في النموذج Photo بهذا الشكل: <?php public function posts() { return $this->morphedByMany(Post::class, 'imageable'); } public function users() { return $this->morphedByMany(User::class, 'imageable'); } افضل شيء للتعلم هو التطبيق يُمكنك تخيل سيناريو في ذهنك و تطبيقه. أيضا بإمكانك الإطلاع على توثيق موسوعة حسوب: العلاقات مُتعددة الأشكال
  7. بإمكانك إستعمال هذه الطريقة لجلب أكثر منتجات إشتراءاً في آخر شهر: <?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 منتجات شراءً منذ البداية.
  8. يُمكنك عمل ذلك من خلال 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 سيكون المُتغير متاح لكليهما، و بهذه الطريقة يُمكنك تمرير المتغير لأي صفحة أخرى تريد. يمكنك الإطلاع على توثيق موسوعة حسوب الخاص بهذا الموضوع: مشاركة البيانات و مؤلّفو الواجهات
  9. هناك عدة طرق لعمل ذلك في لارافيل بإستخدام eloquent مثلاً فكما قلت أنت لا يوجد تابع last يُمكنك إستخدام التابع latest مع التابع first لتحقيق ذلك بهذه الطريقة: إذا أردنا جلب آخر مستخدم: <?php User::latest()->first(); أو يُمكنك إستعمال التابع orderByDesc مع التابع first: User::orderByDesc('created_at')->first(); أما بخصوص هذا السؤال: يُمكنك ذلك عن طريق إستخدام التابع inRandomOrder و التابع first كما يلي: User::inRandomOrder()->first(); و سيتم جلب مُستخدم عشوائي في كل مرة.
  10. fit-content تسمح للعُنصر بإستعمال المساحة المُتاحة له بدون تجاوز المساحة الأعظمية، يستخدم العُنصر هذه المساحة على حسب المُحتوى الخاص به. لنأخذ المثال التالي: حاوية (section) به 3 اقسام (div) نعطي للحاوية عرض ثابت 700px و نعطي للأقسام القيمة fit-content للعرض بهذا الشكل: <section> <div class="fit-red">Ahmed</div> <div class="fit-red">Ahmed gamal</div> <div class="fit-red"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Mollitia sapiente molestias quia aperiam quas voluptatem, sit fugiat suscipit dolorum? Modi saepe nulla natus architecto porro sunt unde suscipit! Autem, facilis? </div> </section> و التنسيقات التالية: section{ width: 700px; } .fit-red{ background-color: red; padding: 5px 20px; margin-bottom: 20px; width: fit-content; } ستجد أن الdiv الأول والثاني أخذ مساحة على حسب المُحتوى و لو أضفت مُحتوى آخر سيتمدد لكن لن يتجاوز 700px و هذا ما يوضحه الdiv الثالث بالرغم من أن هناك محتوى لكن لم يتجاوز المساحة الأعظمية. رُبما هناك تنسيقات لديها أولوية عندك تمنع من تطبيق التنسيقات الأخرى. لأنها مشطوبة أي أن العناصر لديك تأخذ تنسيق آخر في الخاصية width.
  11. تثبيت webpack سهل جداً و اعرف انك قد قمت بتثبيته، و إنما مُشكلتك في إستعماله و إعداد ملف الإعدادات الخاص به هنا قد تجد بعض التعقيدات، لكن لا تقلق فأنت لم تستخدمه من قبل لذلك ستجد بعض الصعوبة في ذلك و في فهم ما يقوم به المُدرب، من الطبيعي جدا عند تعلمنا لشيء جديد نجده صعب لكن مع مراجعة الدروس و الممارسة أكثر و إستعمال التقنية أكثر في مشروعين أو ثلاثة نتعود على هذه التقنية و نجد أنفسنا قد أتقناها بنسبة كبيرة، أنصحك بالتركيز أكثر مع ما يفعله المُدرب في هذه المرحلة و مُراجعة الدرس أكثر من مرة إذا لم يتضح لك الفهم، كما يُمكنك أيضاً البحث في الأكاديمية او من خلال مُحرك البحث لديك عن أي مصطلح تجده مُبهم او يُمكنك الإستفسار أيضاً، بعد مُدة ستجد أن الأمور واضحة المعالم لديك و ستتمكن من إزالة التعقيد الذي تجده حالياً. بالتوفيق.
  12. يُمكنك إضافة عُنصر span تحت حقل الإدخال الخاص بإسم المُستخدم و إعطائه مُعرف لإستعماله في عرض الرسائل: <span id="availability"></span> ثم بإستعمال مكتبة jquery مثلا تقوم بالتسمع على حدث blur على حقل الإدخال و تنفيذ دالة مُعالجة للحدث تجلب من خلالها قيمة اسم المستخدم ثم إن كان الطول أكثر من 3 تقوم بعمل طلب من خلال ajax أما إن كان الطول أقل من 3 تعرض رسالة الخطأ التي تريد كما هو موضح أدناه: $(function() { $('#username').on('blur', function() { // الإستماع للحدث blur على حقل الإدخال var username = $(this).val(); // جلب القيمة التي أدخلها المُستخدم if (username.length > 3) // التحقق من عدد الحروف $.ajax({ // ارسال طلب ajax url: 'check.php', // إرسال الطلب إلى الصفحة check.php method: "POST", // نوع الطلب Post data: { username: username // إرسال الإسم الذي تم إدخاله }, success: function(data) { // في حالة النجاح // سنُرسل عدد السجلات المطابقة لإسم المُستخدم في قاعدة البيانات // إذا كان عدد السجلات لا يُساوي 0 يعني أن الإسم غير مُتاح // و إلا فإن الإسم مُتاح if (data != '0') { $('#availability').html('<span class="text-danger">إسم المُستخدم غير متاح</span>'); $('#register').attr("disabled", true); } else { $('#availability').html('<span class="text-success">إسم المستخدم متاح</span>'); $('#register').attr("disabled", false); } } }) else{ // عرض رسالة الخطأ الخاصة بعدد الحروف $('#register').attr("disabled", true); $('#availability').html('<span class="text-danger">يجب أن يكون عدد أحرف إسم المستخدم أكبر من 3</span>'); } }); }); لقد قمنا بإرسال الطلب إلى الصفحة check.php سيكون مُحتوى الملف بهذا الشكل: <?php //check.php $con = mysqli_connect("localhost", "root", "root", "test_db"); // عملية الإتصال بقاعدة البيانات if (isset($_POST["username"])) { // التحقق من إرسال إسم المُستخدم في الطلب $username = mysqli_real_escape_string($con, $_POST["username"]); // عمل escape لبعض المحارف التي تُسبب أخطاء في الإستعلام إذا وُجدت $query = "SELECT username FROM users WHERE username = '" . $username . "'"; // الإستعلام الذي سيتم تنفيذه $result = mysqli_query($con, $query); // تنفيذ الإستعلام echo mysqli_num_rows($result); // إرجاع عدد السجلات المُطابقة } و هذا هو مُحتوى صفحة الإشتراك بالكامل: <!DOCTYPE html> <html dir="rtl" lang="ar"> <head> <title>تسجيل عضوية جديدة</title> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@600&display=swap" rel="stylesheet"> <style> body { margin: 0; padding: 0; background-color: #f1f1f1; font-family: 'Cairo', sans-serif; text-align: right; } .box { width: 600px; border: 1px solid #ccc; background-color: #fff; border-radius: 5px; margin-top: 36px; } </style> </head> <body> <div class="container box"> <h3 class="text-center mt-3">تسجيل عضوية جديدة</h3><br /> <div class="form-group"> <label>إسم المستخدم</label> <input type="text" name="username" id="username" class="form-control" autocomplete="off" /> <span id="availability"></span> <br /><br /> <button type="button" name="register" class="btn btn-info" id="register" disabled>إشترك الآن</button> <br /> </div> <br /> <br /> </div> <script> $(function() { $('#username').on('blur', function() { // الإستماع للحدث blur على حقل الإدخال var username = $(this).val(); // جلب القيمة التي أدخلها المُستخدم if (username.length > 3) // التحقق من عدد الحروف $.ajax({ // ارسال طلب ajax url: 'check.php', // إرسال الطلب إلى الصفحة check.php method: "POST", // نوع الطلب Post data: { username: username // إرسال الإسم الذي تم إدخاله }, success: function(data) { // في حالة النجاح // سنُرسل عدد السجلات المطابقة لإسم المُستخدم في قاعدة البيانات // إذا كان عدد السجلات لا يُساوي 0 يعني أن الإسم غير مُتاح // و إلا فإن الإسم مُتاح if (data != '0') { $('#availability').html('<span class="text-danger">إسم المُستخدم غير متاح</span>'); $('#register').attr("disabled", true); } else { $('#availability').html('<span class="text-success">إسم المستخدم متاح</span>'); $('#register').attr("disabled", false); } } }) else{ // عرض رسالة الخطأ الخاصة بعدد الحروف $('#register').attr("disabled", true); $('#availability').html('<span class="text-danger">يجب أن يكون عدد أحرف إسم المستخدم أكبر من 3</span>'); } }); }); </script> </body> </html>
  13. يُمكنك عمل ذلك بعدة طرق و هذه أحد الطرق البسيطة لعمل ذلك، إنشاء صنف DB يحتوي على خاصية للإتصال بقاعدة البيانات إنشاء تابع لهذا الصنف إسمه insert يأخذ مُعاملين إسم الجدول و بيانات المقال على شكل مصفوفة ترابطية نُهيء الإستعلام عن طريق مفاتيح المصفوفة و إسم الجدول نضع الصنف DB داخل ملف إسمه DB.php ثم نستخدم هذا الملف داخل الملف الذي ارسلته كما هو موضح أدناه: الصنف DB: <?php class DB { public $con; // خاصية للكائن لحفظ الإتصال public function __construct() // إنشاء الباني { /* حفظ الإتصال و تعيين الترميز يُمكنك هنا تعديل بيانات الإتصال لديك */ $this->con = mysqli_connect("localhost", "root", "root", "test_db"); mysqli_set_charset($this->con, 'utf8mb4'); if (!$this->con) { echo 'Database Connection Error ' . mysqli_connect_error($this->con); } } /* دالة تأخذ إسم الجدول كمعامل أول و البيانات على شكل مصفوفة ترابطية حيث تكون المفاتيح هي أسماء حقول الجدول تقوم الدالة بإنشاء إستعلام التخزين و تنفيذه */ public function insert($table_name, $data) { /* if table_name = posts and data = ['title' => 'title 1', 'body' => 'post content'], then fields = title,body and values = title 1','post content and query = INSERT INTO posts (title,body) VALUES ('title 1','post content') */ $fields = implode(",", array_keys($data)); $values = implode("','", array_values($data)); $query = "INSERT INTO $table_name ($fields) VALUES ('$values')"; if (mysqli_query($this->con, $query)) { return true; // return true if data inserted } else { echo mysqli_error($this->con); // echo error } } } بعد ذلك نُعدل على الملف الذي أرسلته لإضافة عملية التخزين بالإعتماد على الصنف الذي أنشأناه: <?php include 'DB.php'; // إستدعاء الكلاس DB $db = new DB; // إنشاء كائن من الكلاس $success_message = ''; // تعريف متغير سيحمل رسالة تم الحفظ بنجاح if (isset($_POST["submit"])) { // في حالة إرسال النموذج و الضغط على زر الإضافة /* الدالة mysqli_real_escape_string تُستخدم لعمل escape لبعض المحارف التي تُسبب أخطاء في الإستعلام إذا وُجدت */ $data = array( 'title' => mysqli_real_escape_string($db->con, $_POST['title']), 'body' => mysqli_real_escape_string($db->con, $_POST['body']) ); if ($db->insert('posts', $data)) { // في حالة نجاح التخزين $success_message = 'تم حفظ المقال بنجاح'; } } ?> <!DOCTYPE html> <html dir="rtl" lang="ar"> <head> <title>إضافة مقال</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@600&display=swap" rel="stylesheet"> <style> body { margin: 0; padding: 0; background-color: #f1f1f1; font-family: 'Cairo', sans-serif; text-align: right; } .box { width: 800px; border: 1px solid #ccc; background-color: #fff; border-radius: 5px; margin-top: 36px; } </style> </head> <body> <div class="container box p-3"> <h3 class="text-center mt-3">إضافة مقال جديد</h3> <form method="post"> <label>عنوان المقال</label> <input type="text" name="title" class="form-control" /> <br /> <label>محتوى المقال</label> <textarea name="body" class="form-control" rows="5"></textarea> <br /> <input type="submit" name="submit" class="btn btn-info" value="أضف" /> <!-- عرض رسالة النجاح إذا وُجدت --> <?php if (isset($success_message)) : ?> <span class="text-success"> <?= $success_message ?> </span> <?php endif; ?> </form> </div> </body> </html> تتجلى فائدة البرمجة الكائنية في هذه الحالة أننا لن نقوم في كل مرة بإنشاء إستعلام جديد كلما تغير الجدول و البيانات التي نريد تخزينها و إنما بإستعمال التابع insert فإن العملية ستحدث تلقائياً و ستحدث في الخفاء حيث أن الكلاس DB اخفى عملية التخزين. نقطة إضافية و هي أننا قلصنا مكان التعديل فعملية التخزين إذا ما حدثت مشكلة فيها سنقوم بالبحث عن المُشكلة في مكان واحد وهو التابع insert و حلها فيه.
  14. أظن أنكي تستفسرين بخصوص دورة تطوير التطبيقات باستخدام لغة JavaScript هذه الدورة مُتعلقة بلغة JavaScript و ليس لغة جافا إضافة إلى أنها ليست مجانية لأن جميع الدورات التي تُقدمها الأكاديمية مدفوعة، أما الكتب و المقالات و الدروس المكتوبة ليست مدفوعة و مجانية يُمكنك الإستفادة منها. دورة تطوير التطبيقات باستخدام لغة JavaScript تحتوي على 22 ساعة من الدروس المرئية و تبدأ معك من الصفر و تُركز كثيراً على التطبيق العملي و تحتوي على 5 مسارات: أساسيات لغة JavaScript أساسيات مكتبة React.js أساسيات بيئة Node.js تطوير تطبيق جوال باستخدام React Native تطوير تطبيق محادثة شبيه بتطبيق WhatsApp يُمكنك الحصول على معلومات أكثر فيما يخص الدورة من خلال هذا الرابط: تطوير التطبيقات باستخدام لغة JavaScript.
  15. يُمكنك ذلك عن طريق إستخدام الدالة header و الدالة fputcsv كما هو موضح أدناه: <?php $results = array ( array( "name" => "Kamel Mahmoudi", "email" => "kamel@gmail.com", "age" => 20, "country" => "Saudi Arabia", ), array( "name" => "John Doe1", "email" => "john@foo.com", "age" => 24, "country" => "Jordan", ), array( "name" => "John Doe2", "email" => "john@bar.com", "age" => 31, "country" => "Egypt", ) ); $filename = 'data.csv'; // تعريف مُتغير يحمل إسم الملف /* إستخدام الدالة header لجعل المُتصفح يقوم بتحميل ملف csv */ header("Content-type: text/csv"); // جعل الخرج ملف csv header("Content-Disposition: attachment; filename=$filename");// الملف الذي سيتم تحميله سيأخذ الإسم data.csv /* بما أننا نريد إرسال الملف للمُتصفح مُباشرة بدون إنشائه نستخدم stream: php://output بدل إنشاء ملف بهذا الشكل $output = fopen("filename.csv", "w"); w: يعني أننا فتحنا الملف للكتابة */ $output = fopen("php://output", "w"); /* جلب كافة المفاتيح و جعل أول حرف من كل مفتاح كبير Name, Email, Age, Country */ $header = array_map('ucfirst', array_keys($results[0])); fputcsv($output, $header); // كتابة مُحتوى المُتغير header في أول صف foreach($results as $row) // الدوران على النتائج و كتابة كل صف داخل الملف { fputcsv($output, $row); } fclose($output);// غلق الملف بعد تنفيذ السكربت سيقوم المتصفح بتنزيل ملف بالإسم data.csv يحمل كافة البيانات بهذا الشكل:
  16. يُمكنك عمل ذلك من خلال هذه الطريقة: تعريف مصفوفة ترابطية تضم الكلمات التي تبحث عنها، حيث المفتاح هو الكلمة و القيمة هي عدد التكرار و تكون مبدئياً 0 فتح الملف للقراءة كرر حتى تصل لنهاية الملف: -- إقرأ السطر و خزنه في مُتغير. -- تقسيم السلسلة النصية المُكونة للسطر إلى كلمات و تخزينها في مصفوفة -- من أجل كل كلمة من الكلمات: -----> تحقق أنها أحد الكلمات التي تبحث عنها و إذا وجدتها كذلك إرفع عدد تكرارها بِ 1 إطبع عدد تكرار كل كلمة. و هذا هو الكود الخاص ب الخوارزمية بإستخدام لغة php: <?php /* تعريف مصفوفة بالكلمات التي نريد البحث عن تكرارها مصفوفة ترابطية حيث أن كل كلمة هي المفتاح و القيمة توضح عدد التكرارات مع وضع قيمة التكرار لكل كلمة 0 مبدئياً */ $count_array = ["if" => 0,"lol" => 0]; $file = fopen('data.txt', "r"); // فتح ملف البيانات للقراءة /* عمل حلقة بينما هناك مُحتوى للقراءة و بما أننا لم نصل إلى نهاية الملف */ while(!feof($file)) { $line = trim(fgets($file)); // قراءة سطر كل مرة و مسح المسافات الإضافية في الأول و الأخير و تخزينه في مُتغير /* الدالة explode تُساعدنا في تقسيم سلسلة نصية إلى مصفوفة بإستعمال separator هو أول مُعامل */ $words = explode(" ", $line); // مصفوفة الكلمات المُكونة للسطر الذي قرأناه من الملف /* نقوم بعمل حلقة للمرور على كافة كلمات السطر و من أجل كل كلمة نتحقق إن كانت أحد الكلمات التي نبحث عنها إذا كان الحالة نرفع عدد التكرار للكلمة */ foreach($words as $word) { if (array_key_exists($word, $count_array)) { $count_array[$word]++; } } } /* هذه الحلقة لطباعة عدد تكرار كل كلمة */ foreach ($count_array as $word => $number) { echo $word . " occurred " . $number . " times" . "<br>"; } و هذا مثال لملف data.txt: asd lol rotflol if world lol rotflol world bubu hehe lol gnigni lol if if if lol hehe if world lol asd lol rotflol و هذه نتيجة السكربت: if occurred 5 times lol occurred 7 times
  17. أهلاً بك، إذا كنا سنُحدد على حسب سوق العمل فمجال تطوير تطبيقات الجوال مطلوب أكثر سواء تطبيقات أندرويد أو تطبيقات iOS مُقارنة بمجال تطوير تطبيقات سطح المكتب، خصوصاً في العالم العربي مجال ال Desktop ليس عليه طلب كثير، فإذا كنت أنا من سيختار سأتجه إلى سوق تطبيقات الجوال، هناك مجال آخر مطلوب أيضاً و هو مجال تطوير الويب (مواقع و تطبيقات الويب) فإذا كنت ستختارين إختاري أحدهما : تطوير الويب تطوير تطبيقات الجوال. هناك عدة مجالات أخرى بإمكانك الإطلاع على هذا المقال الذي سيُمهد لكِ الطريق: و الإختيار في الآخر راجع لك حسب ميولك و رغبتك الشخصية. بالتوفيق.
  18. مرحباً مُحمد، هذا الأمر طبيعي يُمكن أن العميل لديه إلتزامات كثيرة تُشغله عن الأمر و لا يدخل كثيراً لحسابه على المنصة، ادري أن العملية لن تُكلفه وقت كثير لكن يوجد هذا النوع من العُملاء. إذا قدمت له مشروع جيد بنفس المواصفات التي طلبها و كان تعاملك معه مُحترم ولم يحدث بينك و بينه مُناوشات او نزاعات فأنصحك أن تتواصل معه و تشرح له أن تقييمه و رأيه في الخدمة التي قدمتها له سيُساعدانك كثيراً في إثبات نفسك و قُدراتك على المنصة و سيجلب لك فرص عمل جديدة، أظن أنه سيتفهم الأمر إذا قرأ رسالتك و سيُقدم لك ما تريد. لكن موضوع التقييم في منصة مُستقل ليس إجباري،أي إذا لم يُرد العميل تقييمك على المشروع لا يوجد هناك ما يُرغمه على ذلك. بالتوفيق.
  19. مرحباً بك، يُمكنك التواصل مع الدعم الفني بهذا الخصوص من خلال: مركز المُساعدة و فتح تذكرة لمُشكلتك و سيقومون بالرد عليك و حل مُشكلتك في أقرب وقت. بالتوفيق.
  20. مرحباً أحمد، من المفروض عند شراء أي سكربت تجد معه توثيق رسمي خاص به، يُوضح لك طريقة تثبيته و كيفية التعامل معه، هناك عدة نقاط يجب الإنتباه لها قبل التثبيت و هي متطلبات الخادم، من إصدار php يجب تحقيقه، الإضافات التي يجب تفعيلها و غيرها من الأمور. بعدها تأتي مراحل التثبيت و في هذه الحالة لن يستطيع أحد مساعدتك إلى التوثيق الرسمي حاول الإطلاع عليه و قراءة مُحتوياته ثم تطبيقها خُطوة بخُطوة للوصول إلى النتيجة المرجوة. بخصوص الخطأ الذي أرفقته: رسالة الخطأ تقول أن الملف Framework.class.php يستعمل الكلاس App\Helpers\LogHelper لكنه لم يجده أي لم يتم تضمينه داخل الملف، المفروض أن عملية تحميل الكلاسات يتكفل بها الautoloader و نحن لا ندري هل السكربت يستخدم autoloader خاص أم الautoloader الخاص ب composer، تأكد من هذه الأمور و كل الحلول ستجدها في التوثيق الخاص بالسكربت. بالتوفيق.
  21. مرحباً محمود، لقد أجبتك مُسبقاً على سؤالك في المساهمة الماضية، ينقصك النُقطة الرابعة التي ذكرتها هنا: عمل set للترميز الخاص بالإتصال لهذا الترميز: utf8mb4 ظننت أنك تستخدم mysqli لكن بما أنك تستخدم pdo يُمكنك تغيير الترميز بهذا الشكل: <?php $conn = new PDO('mysql:host=your-hostname;dbname=your-db;charset=utf8mb4', 'your-username', 'your-password', array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci" )); بالتوفيق.
  22. مرحباً عبد الواحد، غالباً ما أستخدم هذه الحزمة: Laravel Localization لبناء موقع مُتعدد اللغات، لأن بها عدة خصائص و تثبيتها و إستعمالها جداً سهل. فهي تعمل على خزن اللغة المُستخدمة (locale) في الجلسة، و يُمكن إنشاء مسار واحد فقط لعدد من اللغات بهذا الشكل: <?php Route::group(['prefix' => LaravelLocalization::setLocale()], function() { // وضع كافة المسارات التي تحتوي على تعدد لغات هنا // على سبيل المثال // صفحة إتصل بنا Route::get('/contact', function() { return view('contact'); }); }); فإن أردنا التوجه لصفحة إتصل بنا الخاصة باللغة الإنجليزية نذهب الى الرابط: http://url-to-website/en/contact أما إن أردنا التوجه لصفحة إتصل بنا باللغة العربية نذهب الى الرابط: http://url-to-website/ar/contact أما عند الذهاب إلى الرابط: http://url-to-website/contact فسيتم عرض الصفحة باللغة الإفتراضية للموقع. يُمكن عمل publish لملف إعدادات الحزمة لتحديد اللغات التي نريدها في موقعنا. في صفحات العرض نستعمل دوال الترجمة التي يُوفرها الإطار ك ()trans او ()__ أو التوجيه الخاص بُمحرك القوالب blade @lang() هذه الدوال تستخدم ملفات الترجمة الموجودة في المُجلد lang لعرض النصوص و الكلام الثابت في الموقع و الذي يكون معروف مُسبقاً لدى المُطور، و يكون قد ترجمه في كافة الملفات، و بإستعمال الدوال أعلاه يتم عرض النصوص حسب اللغة المُخزنة في الجلسة و يتم تغيير قيمتها على حسب الرابط المُستخدم. أما بخصوص تغير الإتجاه فيُمكن إستخدام خاصية dir في لغة html لتحديد الإتجاه حسب اللغة المُخزنة في الجلسة (يُمكن في أي وقت جلب هذه القيمة عن طريق بعض توابع اللغة): LaravelLocalization::getCurrentLocale() // جلب مفتاح اللغة الحالي LaravelLocalization::getCurrentLocaleDirection() // جلب الإتجاه الحالي rtl or ltr LaravelLocalization::getSupportedLocales() // جلب مصفوفة تضم كل اللغات المدعومة في التطبيق بإستخدام هذه الدوال يُمكننا تحميل ملف التنسيقات الموافق إن وُجد لكل إتجاه ملف تنسيقات خاص به @if(LaravelLocalization::getCurrentLocaleDirection() == 'rtl') <!-- عمل بعض التنسيقات التي نريدها في الإتجاه من اليمين إلى اليسار --> <!-- يُمكن تضمين ملف لتنسيقات هذا الإتجاه --> @else <!-- الإتجاه المُعاكس --> @endif أما بخصوص المُحتوى الغير ثابت أي الذي يأتي من قاعدة البيانات فيُمكنك إستخدام هذه الحزمة: laravel-translatable بحيث لكل نموذج و جدول به أعمدة نريد تخزينها بعدة لغات نُنشئ نموذج آخر و جدول بيانات آخر نضع فيه الأعمدة التي به ترجمة بعدة لغات على سبيل المثال نريد حفظ مقالات بعدة لغات سيكون لدينا نموذج Post و نموذج آخر PostTranslation و كل منهما مربوط مع جدول في قاعدة البيانات ستجد في التوثيق الرسمي للحزمة إضغط هنا للذهاب للتوثيق الرسمي و ستجد أمثلة بالشرح. بالتوفيق.
  23. مرحباً محمود، هناك جزئين في المُشكلة التي تُواجهها جزء التخزين و جزء العرض، حتى تقوم بتخزين الرموز التعبيرية في قاعدة البيانات بالشكل الصحيح تغيير ترميز قاعدة البيانات: 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>"; } بالتوفيق.
  24. مرحباً @Rasha Habeeb يبدو أن الرابط الذي أدرجته ليس رابط معرض أعمالك الشخصي و إنما رابط عام لكل مُستقل يُمكنك مُشاركة رابط حسابك الشخصي الذي يكون بهذا الشكل: https://mostaql.com/u/username او من نفس الصفحة التي أدرجتها يُمكنك الضغط على زر شارك معرض أعمالي و سيعرض لك رابط معرض أعمالك و سيكون بهذا الشكل: https://mostaql.com/u/username/portfolio عُموما بالنسبة لأصحاب المشاريع فهم غالباً يميلون للمُستقلين الذين يملكون تقييم جيد و لهم أعمال مُعتبرة داخل المنصة، ثانياً مجالك هو كتابة المٌحتوى و الترجمة هذا المجال به تنافس كبير جداً و إذا لم تقم بتقديم عرضك في اللحظات الأولى من عرض المشروع فإحتمال قراءة عرضك من طرف صاحب المشروع صغير جداً ناهيك عن تصفح معرض أعمالك، فحتى يتحدث معك صاحب المشروع يجب أولا أن يقرأ عرضك و أن يُقنعه العرض و إذا تصفح معرض أعمالك وجده يتقاطع مع مجال المشروع فيجب أن تلتفت لهذه النقاط: وقت تقديم العرض طريقة تقديم العرض يجب أن تكون مُقنعة و تجذب صاحب العمل. معرض الأعمال ينتمي لنفس مجال المشروع سيكون جيد إذا كان يحتوي على عمل لمشروع سابق لك بنفس خصائص مشروع العميل الحالي. خُذ مثلاً هذا المشروع: هنا لاحظ كمية العروض المقدمة لحد الآن هناك 47 عرض و المشروع له 5 ساعات فقط و مزالت العروض في الزيادة ضع نفسك مكان صاحب العمل كيف ستختار في ظل هذا العدد و الكم الهائل! من العروض ثالثاً يجب أن تكون لديك دقة في إختيار مشاريعك فليست كل المشاريع التي يتم عرضها سيتم إنجازها على المنصة هناك نسبة كبيرة من المشاريع يتم إغلاقها لأسباب كثيرة، على سبيل المثال أنا قدمت 212 عرض قُبلت في 21 و استبعدت في 39 و البقية كلها مشاريع مُغلقة لم يتم إنجازها أي ما يُقارب 72% من العروض. فبالتالي لا تضع حساباتك على إجمالي العروض و إنما على العُروض التي استبعدت فيها. بالتوفيق.
  25. مرحباً بك، يُمكنك ذلك بإستخدام حلقة while و في كل لفة تقوم بجلب أحد الأرقام المُكونة للعدد x: تعريف مُتغير x يحمل قيمة العدد الذي نريد حساب مجموع أرقامه تعريف مُتغير sum يُعبر عن المجموع و نُسند له القيمة 0 مبدئياً مادام x أكبر من 0 ----- نضيف باقي قسمة x على 10 لقيمة المُتغير sum ----- نُسند حاصل قسمة قيمة المُتغير x على 10 للمُتغير x نطبع قيمة المُتغير sum و هذا تطبيق للخوارزمية بلغة جافا: public class Main { public static void main(String[] args) { int x = 23451; int sum = 0; while (x > 0) { sum += x % 10; x = x / 10; } System.out.println(sum); } } في اللفة الأولى مثلاً: x % 10 = 1 => sum = 1 x / 10 = 2345 => x = 2345 و هكذا في بقية اللفات إلى حين تحقق الشرط، بالتوفيق.
×
×
  • أضف...