إنشاء كائنات للبيانات المُستقْبَله

ZaFaR97 • منذ سنتين

السلام عليكم، فكّرت في تنظيم عملي وإنشاء ما يُشبه إطار عملٍ مبسّط.

الهدف منه التّعامل مع api معيّن.

ففكّرت في إنشاء Class لكل نوعٍ من البيانات الممكن استقباله من استجابات الـ api

فمثلًا: الـapi إذا أرسل معلومات عن (رسالة):

فستحمل بيانات الرّسالة، المُرسل، الوسائط المتعلّقة بالرّسالة.

مما يتطلب أثناء البرمجة عمل التّالي مثلًا للوصول لبعض محتويات المصفوفة:

$data['message']['user']['photo']['id']

وما يتبعه من عمليات تحقق مثلًا وغيرِه، وبعض العناصر أسماءها طويلة وغريبة بعض الشيء، مما يسبب تكرارًا وصعوبة في الوصول، وحتّى لو عرفناها كمتغير يطول اسمها بسبب وجود عدّة مصفوفات متداخلة.

ومثلًا فإنّ الـapi يقوم بتقسيم الاسم إلى first وlast فبالتالي تحتاج دائمًا لتعريف متغيرٍ يقوم بإنشاء الاسم كاملاً (الدمج بينها).

#ففكرت:

في تعريف Types على شكل Classes تحمِل جميع المتغيرات القادِمة، وكل نوع في Class منفصل.

بحيث يستهل استدعاءها عند البرمجة (بالإكمال التلقائيّ) ويسهّل عملية التحقق من البيانات المطلوبة والمفقودة في نوعٍ معيّن.

ويسهّل إجراء بعض العمليات الأساسية كـ دالّة تُرجِع الاسم الكامل.

فتصبح العملية:

$message = new Message($data);
$message->user()->photo()->id;

$message->user()->full_name;
// بدلًا من
$data['message']['user']['photo']['id'];

$full_name = $data['message']['user']['first_name'] . ' ' . $data['message']['user']['first_name'];

#السؤال:

هل هذه العمليّة مناسِبة؟ أم غيرُ مناسبَة؟

- مع ملاحظة التّالي:

* الـ class سوف يُسنِد القيم للمتغيرات مباشرة إن لم تكن تحمل نوع آخر بداخلها (مصفوفة) <تصل إلى 30 متغيرًا>

وصححّوا لي، إذا كان (إسناد القيَم لكل المتغيّرات المعرّفة عند انشاء الكائن __construct) عملية صحيحة، أو غير صحيحة؟

* المصفوفات تحمِل نوع جديد (مثل: الوسائط تحمّل مصفوفة من البيانات المختلفة:id, size...)، فستكون عبارة عن دالّة تُرجع نسخة من class بالنوّع الجديد (photo) مثلًا. < أمّا السبب هُنا في جعلها دالّة وليست متغيرًا، فهو لمنعِ تحمِيل الكثير من الكائنات المخزّنة التي قد لا تستعمَل.>

وهلِ الفكرة صحيّة؟ أم أنّها إثقال للتطبيق، والتنفيذ..؟

 

# مثال:

JSON data

{
  "message": {
    "message_id": 10104,
    "from": {
      "id": 12431250,
      "first_name": "Sako",
      "username": "SX12345",
      "language_code": "en"
    },
    "text": "Test Text"
  }
}

Master Class

<?php
namespace Types;

class Types
{
  protected $data;
  protected $requiredFields = [];
  public $hasError = NULL;

  /**
   * set Error if method is not existed in message array
   * @param $method
   * @param $arguments
   * @return null|mixed
   */
  public function __call($method, $arguments)
  {
    if (!$this->has($method)){
      $this->hasError = "field as method $method doesn't exist in " . __CLASS__ . " data";
      error_log($this->hasError);
      return NULL;
    }
    return $method($arguments);
  }

  public function __construct(array $data)
  {
    $this->data = $data;
  }

  protected function validate()
  {
    if (!empty($this->requiredFields)){
      foreach ($this->requiredFields as $requiredField) {
        if (!array_key_exists($requiredField, $this->data)) {
          error_log("field $requiredField doesn't exist, In ".__CLASS__);
          return false;
        }
      }
      return true;
    } else {
      return false;
    }
  }

  public function has(string $field)
  {
    return in_array($field, $this->data);
  }

}

Message Class

<?php
namespace Types;

class Message extends Types
{
  public $id;
  public $text;

  public function __construct(array $data)
  {
    parent::__construct($data);
    $this->id = $data['message_id'];
    $this->text = $data['text'];

    $this->data = $data;

  }

  public function from()
  {
    return new User($this->data[__FUNCTION__]);
  }

}

User Class

<?php
# from always refers to User who send.

class User extends Types {
  public
    $id,
    $first_name,
    $last_name,
    $full_name,
    $username,
    $language_code;

  protected $requiredFields = [
    'id',
    'first_name'
  ];

  public function __construct(array $data)
  {
    parent::__construct($data);
    foreach (get_class_vars(__CLASS__) as $var => $val) {
      $this->$var = $val;
    }
    $this->setFullName();
  }

  private function setFullName(): void
  {
    $this->full_name = $this->first_name . ' '. $this->last_name;
  }

}

 

 

كلمات دليلية: data oop php

ساعد بالإجابة

"إن في قضاء حوائج الناس لذة لا يَعرفها إلا من جربها، فافعل الخير مهما استصغرته فإنك لا تدري أي حسنة تدخلك الجنة."

الإجابات (1)

Ali Majrashi • منذ سنتين

وعليكم السلام ورحمة الله وبركاته 

اتوقع سؤالك عن البيانات المرسله والمستقبل من المستخدم وكيف تحولها الى كلاس ليسهل التعامل معه الي تتكلم عنه شبيه في ORM في اطر العمل الي يعمل map لكل حقول جدول في قاعدة البيانات الى Model 

طبعا للتحقق من البيانات المستقبلة من المستخدم تقدر تنشئ Validator Class يستقبل بيانات وقوانين للتحقق شبيه شبيه بالمستخدم في Laravel والكثير من اطر العمل 

<?php

namespace App\Http\Controllers;

use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * Store a new blog post.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // Store the blog post...
    }
}

وظيفة Validator Class يستقبل بيانات المرسلة باستخدام Request ويمررها مع قوانين لكل مدخل من البيانات للتحقق منها وايضا توفر Methods خاصة بالتحقق من البيانات او ارجاع القيم او الاخطاء والكثير من الامور الرائعه 

هنا نرجع لسؤالك شوي هل اقوم بتحويل المدخلات المرسله من قبل المستخدم الى كلاس هذي وظيفة Request Class في لارافيل اي شي يتعلق بالطلبات يكون تابع لهذا الكلاس وداخله نقدر نوصل لاي بيانات مرسله من قبل المستخدم او حتى بيانات الطلب الاخرى مثل headers ونوع الطلب get post put وغيرها من طلبات http 

انت تحتاج بمشروعك لترتيب الكلاسات وتوزيعهم بالشكل الصحيح ونصيحتي لك ادخل على مشاريع مثل Laravel وتصفح الكود المستخدم في بناء الاطار وتعلم منها اذا ماتحب تعقيد لارافيل عندك اطار Lumen من لارافيل مخصص لبناء API ولايحتوي على كثير من اضافات لارافيل يسهل عليك البحث والتعلم منه 

طريقة التنفيذ مثل ماقلت لك افتح ملفات من سبقك من مشاريع ناجحه لافضل الطرق للتنفيذ هنا ملف Request Class من لارافيل وهو مجرد Wrapper لكلاس آخر من اطار سيمفوني 

https://github.com/laravel/framework/blob/5.7/src/Illuminate/Http/Request.php

وهذا رابط الكلاس في سيمفوني 

https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php

انت تقدر تسوي نفس الشي مسوينه في لارافيل استخدم المكتبات الناجحه واعمل لها Wrapper او استخدمها مباشره وهنا تميز اطار سيمفوني بحيث جميع مكتباته برمجت بطريقة تسمح لها باستخدامها خارج الاطار وبدون قيود تقدر تحدد المكتبات الي تحتاجها بمشروعك وتستخدمها باستخدام composer 

اتمنى اني قدرت اساعد ولو بقليل اذا عندك استفسارات اخرى لاتتردد فكلنا لبعض 

ZaFaR97: شكرًا لك يا عليّ، ما قصّرت، راح أطّلع على ما أوردته أعلاه، وراح أشوف هل فيه أسئلة أخرى تتعلق بالموضوع.. أطرحها هُنا إن شاء الله.

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !