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

سمير عبود

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

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

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

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

    34

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

  1. تُعتبر العلاقات المُتعددة الأشكال من المواضيع المُتقدمة في الإطار، و العديد من المطورين يجهلون إستخدامها، بسبب أنها معقدة قليلاً، يُمكنك عدم إستخدامها لكن توجد بعض الحالات إذا ما استخدمت فيها هذا النوع من العلاقات ستُسهل عليك الكثير من الأمور، لنفترض أنك تعمل على مشروع، و هذا المشروع به مودل إسمه 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'); } افضل شيء للتعلم هو التطبيق يُمكنك تخيل سيناريو في ذهنك و تطبيقه. أيضا بإمكانك الإطلاع على توثيق موسوعة حسوب: العلاقات مُتعددة الأشكال
  2. بإمكانك إستعمال هذه الطريقة لجلب أكثر منتجات إشتراءاً في آخر شهر: <?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 منتجات شراءً منذ البداية.
  3. يُمكنك عمل ذلك من خلال 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 سيكون المُتغير متاح لكليهما، و بهذه الطريقة يُمكنك تمرير المتغير لأي صفحة أخرى تريد. يمكنك الإطلاع على توثيق موسوعة حسوب الخاص بهذا الموضوع: مشاركة البيانات و مؤلّفو الواجهات
  4. هناك عدة طرق لعمل ذلك في لارافيل بإستخدام eloquent مثلاً فكما قلت أنت لا يوجد تابع last يُمكنك إستخدام التابع latest مع التابع first لتحقيق ذلك بهذه الطريقة: إذا أردنا جلب آخر مستخدم: <?php User::latest()->first(); أو يُمكنك إستعمال التابع orderByDesc مع التابع first: User::orderByDesc('created_at')->first(); أما بخصوص هذا السؤال: يُمكنك ذلك عن طريق إستخدام التابع inRandomOrder و التابع first كما يلي: User::inRandomOrder()->first(); و سيتم جلب مُستخدم عشوائي في كل مرة.
  5. 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.
  6. تثبيت webpack سهل جداً و اعرف انك قد قمت بتثبيته، و إنما مُشكلتك في إستعماله و إعداد ملف الإعدادات الخاص به هنا قد تجد بعض التعقيدات، لكن لا تقلق فأنت لم تستخدمه من قبل لذلك ستجد بعض الصعوبة في ذلك و في فهم ما يقوم به المُدرب، من الطبيعي جدا عند تعلمنا لشيء جديد نجده صعب لكن مع مراجعة الدروس و الممارسة أكثر و إستعمال التقنية أكثر في مشروعين أو ثلاثة نتعود على هذه التقنية و نجد أنفسنا قد أتقناها بنسبة كبيرة، أنصحك بالتركيز أكثر مع ما يفعله المُدرب في هذه المرحلة و مُراجعة الدرس أكثر من مرة إذا لم يتضح لك الفهم، كما يُمكنك أيضاً البحث في الأكاديمية او من خلال مُحرك البحث لديك عن أي مصطلح تجده مُبهم او يُمكنك الإستفسار أيضاً، بعد مُدة ستجد أن الأمور واضحة المعالم لديك و ستتمكن من إزالة التعقيد الذي تجده حالياً. بالتوفيق.
  7. يُمكنك إضافة عُنصر 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>
  8. يُمكنك عمل ذلك بعدة طرق و هذه أحد الطرق البسيطة لعمل ذلك، إنشاء صنف 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 و حلها فيه.
  9. أظن أنكي تستفسرين بخصوص دورة تطوير التطبيقات باستخدام لغة JavaScript هذه الدورة مُتعلقة بلغة JavaScript و ليس لغة جافا إضافة إلى أنها ليست مجانية لأن جميع الدورات التي تُقدمها الأكاديمية مدفوعة، أما الكتب و المقالات و الدروس المكتوبة ليست مدفوعة و مجانية يُمكنك الإستفادة منها. دورة تطوير التطبيقات باستخدام لغة JavaScript تحتوي على 22 ساعة من الدروس المرئية و تبدأ معك من الصفر و تُركز كثيراً على التطبيق العملي و تحتوي على 5 مسارات: أساسيات لغة JavaScript أساسيات مكتبة React.js أساسيات بيئة Node.js تطوير تطبيق جوال باستخدام React Native تطوير تطبيق محادثة شبيه بتطبيق WhatsApp يُمكنك الحصول على معلومات أكثر فيما يخص الدورة من خلال هذا الرابط: تطوير التطبيقات باستخدام لغة JavaScript.
  10. يُمكنك ذلك عن طريق إستخدام الدالة 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 يحمل كافة البيانات بهذا الشكل:
  11. يُمكنك عمل ذلك من خلال هذه الطريقة: تعريف مصفوفة ترابطية تضم الكلمات التي تبحث عنها، حيث المفتاح هو الكلمة و القيمة هي عدد التكرار و تكون مبدئياً 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
  12. أهلاً بك، إذا كنا سنُحدد على حسب سوق العمل فمجال تطوير تطبيقات الجوال مطلوب أكثر سواء تطبيقات أندرويد أو تطبيقات iOS مُقارنة بمجال تطوير تطبيقات سطح المكتب، خصوصاً في العالم العربي مجال ال Desktop ليس عليه طلب كثير، فإذا كنت أنا من سيختار سأتجه إلى سوق تطبيقات الجوال، هناك مجال آخر مطلوب أيضاً و هو مجال تطوير الويب (مواقع و تطبيقات الويب) فإذا كنت ستختارين إختاري أحدهما : تطوير الويب تطوير تطبيقات الجوال. هناك عدة مجالات أخرى بإمكانك الإطلاع على هذا المقال الذي سيُمهد لكِ الطريق: و الإختيار في الآخر راجع لك حسب ميولك و رغبتك الشخصية. بالتوفيق.
  13. مرحباً مُحمد، هذا الأمر طبيعي يُمكن أن العميل لديه إلتزامات كثيرة تُشغله عن الأمر و لا يدخل كثيراً لحسابه على المنصة، ادري أن العملية لن تُكلفه وقت كثير لكن يوجد هذا النوع من العُملاء. إذا قدمت له مشروع جيد بنفس المواصفات التي طلبها و كان تعاملك معه مُحترم ولم يحدث بينك و بينه مُناوشات او نزاعات فأنصحك أن تتواصل معه و تشرح له أن تقييمه و رأيه في الخدمة التي قدمتها له سيُساعدانك كثيراً في إثبات نفسك و قُدراتك على المنصة و سيجلب لك فرص عمل جديدة، أظن أنه سيتفهم الأمر إذا قرأ رسالتك و سيُقدم لك ما تريد. لكن موضوع التقييم في منصة مُستقل ليس إجباري،أي إذا لم يُرد العميل تقييمك على المشروع لا يوجد هناك ما يُرغمه على ذلك. بالتوفيق.
  14. مرحباً بك، يُمكنك التواصل مع الدعم الفني بهذا الخصوص من خلال: مركز المُساعدة و فتح تذكرة لمُشكلتك و سيقومون بالرد عليك و حل مُشكلتك في أقرب وقت. بالتوفيق.
  15. مرحباً أحمد، من المفروض عند شراء أي سكربت تجد معه توثيق رسمي خاص به، يُوضح لك طريقة تثبيته و كيفية التعامل معه، هناك عدة نقاط يجب الإنتباه لها قبل التثبيت و هي متطلبات الخادم، من إصدار php يجب تحقيقه، الإضافات التي يجب تفعيلها و غيرها من الأمور. بعدها تأتي مراحل التثبيت و في هذه الحالة لن يستطيع أحد مساعدتك إلى التوثيق الرسمي حاول الإطلاع عليه و قراءة مُحتوياته ثم تطبيقها خُطوة بخُطوة للوصول إلى النتيجة المرجوة. بخصوص الخطأ الذي أرفقته: رسالة الخطأ تقول أن الملف Framework.class.php يستعمل الكلاس App\Helpers\LogHelper لكنه لم يجده أي لم يتم تضمينه داخل الملف، المفروض أن عملية تحميل الكلاسات يتكفل بها الautoloader و نحن لا ندري هل السكربت يستخدم autoloader خاص أم الautoloader الخاص ب composer، تأكد من هذه الأمور و كل الحلول ستجدها في التوثيق الخاص بالسكربت. بالتوفيق.
  16. مرحباً محمود، لقد أجبتك مُسبقاً على سؤالك في المساهمة الماضية، ينقصك النُقطة الرابعة التي ذكرتها هنا: عمل 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" )); بالتوفيق.
  17. مرحباً عبد الواحد، غالباً ما أستخدم هذه الحزمة: 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 و كل منهما مربوط مع جدول في قاعدة البيانات ستجد في التوثيق الرسمي للحزمة إضغط هنا للذهاب للتوثيق الرسمي و ستجد أمثلة بالشرح. بالتوفيق.
  18. مرحباً محمود، هناك جزئين في المُشكلة التي تُواجهها جزء التخزين و جزء العرض، حتى تقوم بتخزين الرموز التعبيرية في قاعدة البيانات بالشكل الصحيح تغيير ترميز قاعدة البيانات: 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>"; } بالتوفيق.
  19. مرحباً @Rasha Habeeb يبدو أن الرابط الذي أدرجته ليس رابط معرض أعمالك الشخصي و إنما رابط عام لكل مُستقل يُمكنك مُشاركة رابط حسابك الشخصي الذي يكون بهذا الشكل: https://mostaql.com/u/username او من نفس الصفحة التي أدرجتها يُمكنك الضغط على زر شارك معرض أعمالي و سيعرض لك رابط معرض أعمالك و سيكون بهذا الشكل: https://mostaql.com/u/username/portfolio عُموما بالنسبة لأصحاب المشاريع فهم غالباً يميلون للمُستقلين الذين يملكون تقييم جيد و لهم أعمال مُعتبرة داخل المنصة، ثانياً مجالك هو كتابة المٌحتوى و الترجمة هذا المجال به تنافس كبير جداً و إذا لم تقم بتقديم عرضك في اللحظات الأولى من عرض المشروع فإحتمال قراءة عرضك من طرف صاحب المشروع صغير جداً ناهيك عن تصفح معرض أعمالك، فحتى يتحدث معك صاحب المشروع يجب أولا أن يقرأ عرضك و أن يُقنعه العرض و إذا تصفح معرض أعمالك وجده يتقاطع مع مجال المشروع فيجب أن تلتفت لهذه النقاط: وقت تقديم العرض طريقة تقديم العرض يجب أن تكون مُقنعة و تجذب صاحب العمل. معرض الأعمال ينتمي لنفس مجال المشروع سيكون جيد إذا كان يحتوي على عمل لمشروع سابق لك بنفس خصائص مشروع العميل الحالي. خُذ مثلاً هذا المشروع: هنا لاحظ كمية العروض المقدمة لحد الآن هناك 47 عرض و المشروع له 5 ساعات فقط و مزالت العروض في الزيادة ضع نفسك مكان صاحب العمل كيف ستختار في ظل هذا العدد و الكم الهائل! من العروض ثالثاً يجب أن تكون لديك دقة في إختيار مشاريعك فليست كل المشاريع التي يتم عرضها سيتم إنجازها على المنصة هناك نسبة كبيرة من المشاريع يتم إغلاقها لأسباب كثيرة، على سبيل المثال أنا قدمت 212 عرض قُبلت في 21 و استبعدت في 39 و البقية كلها مشاريع مُغلقة لم يتم إنجازها أي ما يُقارب 72% من العروض. فبالتالي لا تضع حساباتك على إجمالي العروض و إنما على العُروض التي استبعدت فيها. بالتوفيق.
  20. مرحباً بك، يُمكنك ذلك بإستخدام حلقة 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 و هكذا في بقية اللفات إلى حين تحقق الشرط، بالتوفيق.
  21. مرحباً بك، رُبما تجد بعض النصائح المٌفيدة لك في هذه المُشاركة على مُجتمع حسوب: تريد الدخول الى ثيم فورست اسألني ما تشاء، أظن أن تقليد بعض الأفكار مسموح به لكن ليس نفس الثيم، لديهم العديد من المعايير التي يجب عليك مراعاتها و إلا لن يتم قبول القالب الخاص بك. أكيد بعد البيع لأنك في المنصة تبيع منتجات، بالإضافة إلى أن هناك نسبة تأخذها المنصة و هي 50% و تتغير النسبة مع الوقت. بالتوفيق.
  22. مرحباً إسماعيل، إذا كان لكل مُنتج عدة أكواد فالعلاقة التي تربط المنتج بالكود هي واحد لمُتعدد (hasMany) و بما أن كل كود ينتمي لمُنتج واحد فالعلاقة في النموذج (Code) ستكون (belongsTo): لم أفهم ماذا يعني الحقل number_of_products وهل في الموقع الخاص بك المُستخدم سيشتري الأكواد أم ماذا؟ أي أن نتيجة عملية الشراء سيتحصل عل أحد أكواد المنتج ؟ إذا كان المُستخدم سيحصل في الأخير على كود من هذه الأكواد فأقترح إضافة حقل جديد purchased_at لجدول codes: $table->datetime('purchased_at')->nullable(); لتخزين وقت الشراء. و يُمكن أيضاً إضافة حقل user_id لتخزين مُعرف المُستخدم الذي قام بشراء الكود و جعله null إفتراضياً. العلاقات ستكون بهذا الشكل: النموذج Product: <?php class Product extends Model{ // ... public function codes() { return $this->hasMany(Code::class); } public function purchasedCodes() { return $this->hasMany(Code::class)->whereNotNull('purchased_at'); } } أما النموذج Code: <?php class Code extends Model { // ... public function product() { return $this->belongsTo(Product::class); } public function purchased_by() { return $this->belongsTo(User::class, 'user_id'); } } يُمكن أيضاً إضافة جدول و نموذج آخر للمشتريات (purchases) و تربط النموذج Purchase بكل من النموذج User و Code: <?php class Purchase extends Model { // ... public function user() { return $this->belongsTo(User::class, 'user_id'); } public function code() { return $this->belongsTo(Code::class, 'code_id'); } } بالتوفيق.
  23. مرحباً @مشاعل علي2 بانضمامك لأي دورة من دورات الأكاديمية ستحصلين على وصول لمحتوياتها كاملة مدى الحياة. دورات أكاديمية حسوب لا تستبدل و لا تنتهي صلاحيتها بل تحدّث باستمرار لتواكب التطورات. هذا يعني أنكِ إنْ انضممت الآن، ستحصلين على جميع التحديثات المستقبلية لها مجاناً دون دفع تكلفة إضافيّة، و لا تحتاجين التقيد بوقت مُحدد لإتمامها أيضاً عند إشتراكك بأحد الدورات سيتم فتح المسارات الأولى من بقية الدورات مسار الأساسيات من كل دورة و ذلك لمُساعدة الطلاب على التعرف على المجالات الأخرى، بالإضافة لوجود فريق كامل من المُدربين للإجابة على كافة الإستفسارات و مُساعدتك على حل المشاكل التي تواجهك أثناء مُتابعتك للدورة. بالتوفيق.
  24. مرحباً @Abdoo Qa يُمكنك تعلم أساسيات البرمجة بالإعتماد على أية لغة برمجة، لكن يُستحسن أن تكون اللغة كائنية التوجه، تخدم الهدف الذي تريد من أجله تعلم البرمجة، سهلة التعلم، متعددة المجالات، أنصحك بالإطلاع على هذا المقال لأنه سيُسهل و يختصر عليك الكثير: أنصحك بالإطلاع على المقال و قرائته بعدها حدد المجال الذي تُحبه و من ثم يمكنك تحديد اللغة التي تتعلمها. تُعتبر لغة بايثون خيار جيد لك، بحكم أنها من بين أسهل اللغات في التعلم و ذلك حسب إستطلاعات قامت بها عدة شركات و مواقع مثل stackoverflow و github و تُعتبر أيضاً من بين أكثر اللغات حُباً لدى المُبرمجين حسب إحصائيات شركة hired، أيضاً تدخل في عدة مجالات من بينها تطوير المواقع، تطوير برامج سطح المكتب، الذكاء الإصطناعي، تحليل البيانات و غيرها من المجالات الأخرى، ملاحظة: بتعلمك للبرمجة و أساسياتها بأي لغة كانت و لنقل أن اللغة إسمها 'أ' ستتمكن من الإنتقال لأي لغة أخرى مهما كانت بالإلمام بطريقة الكتابة (syntax) أما اساسيات البرمجة فستبقى نفسها لن تتغير. بالتوفيق.
  25. مرحباً عبد الواحد، إن مفهوم الseeders جاء ليُكمل مفهومي الmigrations و الfactories فملفات التهجير تُساعدنا في إنشاء الهيكلية العامة لجداول قاعدة البيانات بما فيها من حقول هذه الجداول و تعيين أنواع البيانات لهذه الحقول ، القيم الإفتراضية لها، تحديد القيود لهذه الأعمدة، إضافة أعمدة جديدة لجدول مُحدد، ربط الجداول بمفاتيح ثانوية و ما إلى ذلك من خصائص ضمن قواعد البيانات تم توفيرها للإستخدام ضمن ملفات التهجير، تتجلى فائدة مفهوم التهجير بشكل كبير إذا كنت تعمل ضمن فريق من المُطورين، لنفترض أن المفهوم غير موجود و بالتالي سيكون على كل شخص رفع نُسخة من قاعدة البيانات التي يعمل عليها، و سيتكفل بشرح الأشياء التي أضافها و سيتوجب على بقية أعضاء الفريق فهم الأشياء المُضافة و سيضيع وقت كثير في هذا الأمر ، الشيء الذي جعل المُطورين يقومون بإنشاء مفهوم مُتعارف عليه بينهم يُسهل عملية التعامل مع جداول قاعدة البيانات من خلال ملفات و كلاسات و أسطر برمجية غير مُعقدة، بالإضافة إلى الأوامر المتعددة من خلال واجهة artisan، الآن بوجود هذا المفهوم لن يضطر أي شخص شرح أو توضيح الأشياء المُضافة، بل سيتعين على الأشخاص العاملين على المشروع قراءة ملفات التهجير و سيفهمون بكل سهولة، و بإعتمادهم على الأوامر المتاحة سيتمكنون من بناء و هدم جداول قاعدة البيانات بكل سهولة . حتى و إن كان المُطور يعمل لوحده سيحتاج لإستخدام ملفات التهجير و ستُساعده في إنشاء قاعدة بيانات المشروع في وقت قصير ، فلتُجرب عدم إستخدامها في مشروع و لتقم مثلا بإنشاء قاعدة البيانات بإستخدام أوامر sql او واجهة برنامج مثل phpmyadmin ستستغرق وقت و سيصعب عليك الأمر خصوصاً إذا لم تكن لديك خلفية و معرفة بكيفية التعامل مع قواعد البيانات، لنقل على سبيل المثال أنه واجهتك مُشكلة برمجية و أردت من شخص ما أن يُساعدك فسيجد هو أيضاً صعوبة في الوصول إلى المُشكلة قبل حلها. أما مفهوم الfactories فتٌعتبر مصانع لإنشاء سجلات او كائنات من نموذج مُحدد مثلاً نموذج المُستخدم سيكون له مصنع لإنشاء مُستخدمين، نموذج المقالات سيكون له مصنع لإنشاء المقالات وهكذا، أما مفهوم الseeders فهي تُساعدنا في إنشاء بيانات إختبارية، لنختبر مميزات الموقع و خصائصه و تُساعدنا و تُسهل علينا هذه العملية و تعمل بإستخدام الfactories . عملية البذر يُمكن أن نقول أنها ضرورية لإنشاء بيانات إختبارية لتجربة الموقع أثناء مرحلة التطوير، لنقل أنك قمت بتوفير بعض الخصائص في الموقع و تريد أن يقوم شخص ما بتجربة هذه الخصائص سواء كان صديقك أو عميل تقوم بإنجاز المشروع له أو حتى أنت، فكيف ستُجرب هذه الخصائص بدون وجود بيانات في قاعدة البيانات، هل ستقوم بإنشائها يدوياً ، لا تنسى أن بعض الجداول مُرتبطة ببعضها البعض فعند إنشائك لسجل مُستخدم مثلاً عليك إنشاء سجل profile و تربط بينهما و هذا الأمر صعب و يأخذ وقت إن كانت العملية يدوياً بعكس إستخدام الseeders. برأيي أن بذر بيانات تجريبية لا يُمكن الإستغناء عنه في مرحلة التطوير ، أما الطريقة فلك حرية الإختيار سواء كانت التي تُكلفك عناء و جهد إضافي (الطريقة اليدوية) أو الطريقة التي تُساعدك (وهي إستخدام الseeders) حتى عند إستخدامك للإختبارات بشتى أنواعها كالأحادية (unit tests) و غيرها تحتاج إلى بيانات تجريبية بالتوفيق.
×
×
  • أضف...