پکیج‌ها

در جالنو برای مدیریت و کاربا پکیج‌های پروژه کلاس packages\base\Package تعریف شده است. از این کلاس زمان کار با فایل‌ها برای دسترسی به فایل موجود در پکیج، آدرس فایل و ... استفاده میشود.

در کلاس Package متد‌های زیر تعریف شده است.

متد کاربرد
fromName(string $name): Package گرفتن پکیج
getName(): string گرفتن نام پکیج والد
getFilePath(string $file): string گرفتن آدرس فایل
url(string $file, bool $absolute): string گرفتن آدرس فایل
getFile(string $path): File\Local گرفتن یک فایل
getHome(): Directory گرفتن مشخصات پکیج بصورت شئ از کلاس Directory
getFileContents(string $file): string خواندن محتویات فایل
getOption(string $name): ?mixed گرفتن تنظیم تعریف شده برای پکیج
setOption(string $name, mixed $value) افزودن تنظیم جدید برای پکیج
bootup() فراخوانی فایل bootstrap در صورتی که در پکیج تنظیم شده باشد
این متد توسط فرم ورک و در زمان بارگذاری پکیج ها فراخوانی میشود

فرمورک از متدهای getter , setter زیر برای کامل کردن اطلاعات پیکج استفاده میکند.

متد کاربرد
addDependency(string $dependency) اضافه کردن پکیج وابسته
getDependencies(): array گرفتن نام پکیج‌های وابسته
addFrontend(string $source) افزودن پکیج قالب
getFrontends(): array گرفتن نام پکیج‌های معرفی شده برای قالب
setBootstrap(string $bootstrap) افزودن فایل bootstrap
setRouting(string $routing) تنظیم فایل مسیریابی
getRouting(): ?File گرفتن فایل مسیریابی
getRoutingRules(): array گرفتن آدرس‌های مسیریابی مشخص شده در فایل routing.json
getConfigFile(): File گرفتن فایل پیکربندی (package.json) پیکج

دسترسی به پکیج

در کلاس packages\base\Package متد fromName برای دسترسی به پکیج‌های پروژه تعریف شده است. علاوه بر متد fromName با فراخوانی متد package که در کلاس packages\base\Packages ،تعریف شده است نیز میتوانید به پکیج‌های پروژه دسترسی داشته باشید. متدهای fromName و package برای سهولت بصورت static تعریف شده‌اند.

خروجی متد‌های fromName و package درصورتی که پکیج مشخص شده موجود باشد شئ از کلاس packages\base\Package است که حاوی مشخصات پکیج مانند پکیج‌های وابسته ، فایل مسیریاب ،فایل‌های مترجم و بطور کلی تمامی تنظیماتی که در فایل ساختار پیکج (package.json) تنظیم شده است می‌باشد.

درصورتی که پکیج مشخص شده موجود نباشد استثنا‌packages\base\IO\NotFoundException پرتاب می‌شود.

دسترسی به پکیج از طریق متد package

use packages\base\Packages;

$package = Packages::package("packagename");

دسترسی به پکیج از طریق متد fromName

use packages\base\Package;

$package = Package::fromName("packagename");

آدرس فایل

برای دسترسی به آدرس فایل‌ها دو متد getFilePath و url تعریف شده است. هر دو متد به عنوان ورودی آدرس و نام فایل را بصورت رشته دریافت میکنند. فایل معرفی شده میتواند موجود نباشد.

اگر به آرگومان دوم متد url مقدار true داده شود آدرس را بطور کامل (در قالب آدرس url) برمیگرداند. مقدار پیش‌فرض این آرگومان false میباشد.

تفاوت متد getFilePath و url

از متد getFilePath برای دریافت آدرس فایل در داخل پکیج و از متد url برای دریافت آدرس اینترنتی فایل استفاده میشود.

مثال 1

<?php
namespace packages\packagename\controllers;

use themes\themename\views;
use packages\base\{Controller, Response, View, Packages, IO\File};

class Albums extends Controller {

    public function insertImg(): Response {

        $view = view::byName(views\Albums\InsertImg::class);
        $this->response->setView($view);

        if (Http::is_post()){
            $inputs = $this->checkinputs([
                'img' =>[
                    'type' => 'image',
                    "max-size" => 2097152 // Byte
                    "obj" => true, 
                    "extension" => array('jpeg', 'jpg']
                ]
            ]);

            $path = 'storage/public/albums/' . $inputs['img']->getFile()->md5() . '.' . $inputs['img']->getExtension();
            $img = new File\Local(Packages::package('packagename')->getFilePath($path));
            /**
             * Or
             * $img = Packages::package('packagename')->getFile($path);
             */
            $directory = $img->getDirectory();
            if (!$directory->exists()) {
                $directory->make(true);
            }
            $inputs['img']->copyTo($img);
        }

        $this->response->setStatus(true);
        return $this->response;
    }
}

در مثال فوق ابتدا در $path آدرس محل ذخیره فایل را ایجاد میکنیم سپس $path را به متد getFilePath داده که آدرس دقیق فایل مطابق package موردنظر ایجاد شود.

خروجی متد getFilePath بصورت زیر میباشد.

packages/packagename/storage/public/albums/0bc27259aae45199b214898a48d0a7bf.jpg

برای اطلاعات بیشتر در رابطه با فایل ها و دایرکتوری ها به صفحات کار با فایل‌ها و پوشه‌ها مراجعه کنید.

مثال 2

<?php
namespace packages\packagename\controllers;

use packages\base\{Controller, Response, Packages, NotFound, ResponseFile};

class Albums extends Controller {

    public function download($data): Response {
        $file = Packages::package('packagename')->getFile($data["path"]);
        if (!$file->exists()) {
            throw new NotFound();
        }
        $responsefile = new ResponseFile();
        $responsefile->setLocation(Packages::package('packagename')->getFilePath($file->path));
        $responsefile->setSize($file->size);
        $responsefile->setName($file->name);
        $this->response->setFile($responsefile);

        $this->response->setStatus(true);
        return $this->response;
    }
}

در مثال فوق قصد داریم فایلی را برای دانلود به کاربر بدهیم. ابتدا شئ از کلاس فایل مطابق آدرس دریافت شده دریافت کرده و وجود فایل را بررسی میکنیم.

برای اطلاعات بیشتر به صفحه پاسخ مراجعه کنید.

مثال 3 استفاده از متد url در قالب

<?php
namespace themes\themename\views\profile;

use packages\packagename\User as Model;
use packages\base\{Packages, frontend\Theme, views\Form};
use themes\clipone\{ViewTrait, views\FormTrait, views\TabTrait}; // Clipone is userpanel package theme name

class edit extends Form {

    use ViewTrait, FormTrait, TabTrait;

    protected $user;

    public function __beforeLoad(){
        $this->setTitle(t('profile.edit'));

        $this->addBodyClass('profile');
        $this->addBodyClass('profile_edit');
    }

    protected function getAvatarURL(): string {
        if ($this->user->avatar_path) {
            return Packages::package('userpanel')->url($this->user->avatar_path);
        }

        return Theme::url('assets/images/defaultavatar.jpg');
    }

    public function setUser(Model $user) {
        $this->user = $user;
    }
}
<div class="img-profile">
    <img class="img-responsive img-circle" src="<?php echo $this->getAvatarURL(); ?>">
    <h4 class="user-name">
        <i class="fa fa-user"></i>
    <?php echo $this->user->name; ?>
    </h4>
</div>

خواندن محتویات صفحه

متد getFileContents برای خواندن محتویات فایل تعریف شده است. این متد به عنوان آرگومان ورودی آدرس و نام فایل موجود در پکیج را بصورت رشته دریافت میکند. در صورتی که فایل موجود نباشد استثنا packages\base\IO\NotFoundException پرتاب می‌شود.

مثال

<?php
namespace packages\packagename\controllers;

use themes\themename\views;
use packages\base\{View, Controller, Packages, view\Error};

class Main extends Controller {

    public function description() {

        $view = view::byName(views\main\Description::class);
        $this->response->setView($view);

        try {
            $description = Packages::package('packagename')->getFileContents("storage/public/description.txt");
            $view->setData($description, 'description');
        } catch(IO\NotFoundException $e) {
            throw new Error("file_not_exists");
        }

        $this->response->setStatus(true);
        return $this->response;
    }
}

در مثال فوق محتویات فایل را با متد getFileContents گرفته و در متد setData به view منتقل می‌شود.

گرفتن فایل

متد getFile آدرس و نام فایل را بصورت رشته گرفته و خروجی آن شئ از کلاس File میباشد. فایل مشخص شده میتواند موجود نباشد.

مثال

<?php
namespace packages\packagename\controllers;

use themes\themename\views;
use packages\base\{Controller, Response, View, Http, Packages};

class Main extends Controller {

    public function addDescription(): Response {

        $view = View::byName(views\main\AddDescription::class);
        $this->response->setView($view);

        if (Http::is_post()) {

            $input = $this->checkinputs([
                'description' =>[
                    'type' => 'string'
                ]
            ]);

            $file = Packages::package('packagename')->getFile("storage/public/description.txt");

            $directory = $file->getDirectory();
            if (!$directory->exists()) {
                $directory->make(true);
            }

            $file->write($input['description']);
        }

        $this->response->setStatus(true);
        return $this->response;
    }
}

در مثال فوق فایل مورد نظر را با فراخوانی متد getFile گرفته سپس از وجود دایرکتوری والد آن اطمینان حاصل میشود (اگر دایرکتوری والد موجود نباشد با فراخوانی متد make ایجاد می‌شود.) سپس متن دریافت شده از ورودی در فایل نوشته می‌شود. اگر فایل موجود نباشد با فراخوانی متد write ایجاد و متن در آن نوشته میشود. در صورت وجود فایل متن جایگزین متن قبلی می‌شود.

اضافه کردن تنظیمات جدید

علاوه بر کلیدهای routing, frontend, autoload , ... که در فایل ساختار پکیج تعریف شده‌اند و باید مقداردهی شوند؛ فرمورک این امکان را به برنامه نویسان میدهد تا بتوانند تنظیماتی را در فایل ساختار بسته‌ها اضافه کنند و در روند برنامه از آن استفاده کنند.

بطور مثال برنامه نویس آدرس محل ذخیره فایل‌های آپلود شده را در این فایل تنظیم میکند و در برنامه بجای استفاده از آدرس ایستا تنظیمات پکیج را فراخوانی میکند.

برای فراخوانی تنظیمات متد getOption تعریف شده است. آرگومان ورودی متد کلید تنظیم میباشد.

علاوه‌بر معرفی تنظیمات در فایل ساختار میتوانید تنظیمات مورد نظر را با استفاده از متد setOption در روند برنامه تنظیم کنید ولیکن باید توجه داشته باشید، این تنظیم باید قبل از فراخوانی و دریافت، مقدار دهی شده باشد.

توجه : در این روش تنظیم ذخیره نشده و فقط تا پایان همان درخواست قابل فراخوانی است

نمونه فایل پیکربندی

{
    "permissions": "*",
    "routing": "routing.json",
    "frontend": "frontend",
    "autoload": {
        "directories": ["controllers", "Models", "listeners", "events"]
    },
    "dependencies": ["userpanel"],
    "languages":{
        "fa_IR": "langs/fa_IR.json",
        "en_US": "langs/en_US.json"
    },
    "events": [
        {
            "name": "packages/userpanel/events/usertype_permissions_list",
            "listener": "listeners/settings/usertypes/Permissions@list"
        }
    ],
    "upload_path": "storage/public/upload/"
}

مثال: نحوه استفاده از تنظیمات

<?php
namespace packages\packagename\controllers;

use themes\themename\views;
use packages\packagename\User as Model;
use packages\base\{Controller, Response, View, Packages, NotFound};

class Users extends Controller {

    public function updateAvatar($data): Response {

        $user = Model::byId($data['id']);
        if (!$user) {
            throw new NotFound;
        }

        $view = view::byName(views\user\Info::class);
        $this->response->setView($view);

        $inputs = $this->checkinputs([
            'img' =>[
                'type' => 'image',
                "max-size" => 2097152 // Byte
                "obj" => true, 
                "extension" => array('jpeg', 'jpg'],
                "resize" => [200, 200]
            ]
        ]);

        $package = Packages::package('packagename');

        $path = $package->getOption("upload_path") . $inputs["img"]->getFile()->md5() . "." . $inputs["img"]->getExtension();

        $file = Packages::package("packagename")->getFile($path);
        if (!$file->exists()) {
            $directory = $file->getDirectory();
            if (!$directory->exists()) {
                $directory->make(true);
            }

            $image->saveToFile($file);
        }

        $user->avatar = $path;
        $user->save();

        $this->response->setData($package->url($path, true), "path");

        $this->response->setStatus(true);
        return $this->response;
    }
}

فایل bootstrap

در فرمورک کلیدی تحت عنوان bootstrap تعریف شده است. در این کلید آدرس فایل php را معرفی میکنید و فرمورک بعد از بارگذاری پکیج و قبل از پیدا کردن آدرس‌ها و کنترلرها این فایل را فراخوانی و اجرا میکند. از این فایل برای انجام عمیاتی مانند بررسی ‌‌‌IP کاربر که قبل از اجرای برنامه باید چک شود استفاده می‌شود.

فرمورک عملیات اضافه کردن فایل bootstrap و فراخوانی آن را با استفاده از متدهای setBootstrap و bootup به صورت خودکار انجام میدهد.

معرفی فایل bootstrap در فایل package.json

{
    "permissions": "*",
    "routing": "routing.json",
    "frontend": "frontend",
    "autoload": {
        "directories": ["controllers", "Models", "listeners", "events", "bootstraps"]
    },
    "dependencies": ["userpanel"],
    "languages":{
        "fa_IR": "langs/fa_IR.json",
        "en_US": "langs/en_US.json"
    },
    "events": [
        {
            "name": "packages/userpanel/events/usertype_permissions_list",
            "listener": "listeners/settings/usertypes/Permissions@list"
        }
    ],
    "bootstrap": "bootstraps/checkAccess.php"
}

نمونه فایل bootstrap

<?php
namespace packages\packagename\bootstraps;

use packages\base\{Http, NotFound};
use packages\packagename\BannedIP as Model;

$userIP = Http::$client["ip"];

$model = new Model();
$model->where("ip", $userIP);
if ($model->has()) {
    throw new NotFound();
}