Skip to main content
Version: Current

The Package Class

In Jalno, the packages\base\Package class is defined for managing and working with a project's packages. This class is used when working with files—to access a file within a package, get a file's path, and so on.

The following methods are defined in the Package class:

MethodPurpose
fromName(string $name): PackageGet a package
getName(): stringGet the name of the parent package
getFilePath(string $file): stringGet a file's path
url(string $file, bool $absolute): stringGet a file's URL
getFile(string $path): File\LocalGet a file
getHome(): DirectoryGet the package's details as an object of the Directory class
getFileContents(string $file): stringRead a file's contents
getOption(string $name): ?mixedGet an option defined for the package
setOption(string $name, mixed $value)Add a new option for the package
bootup()Call the bootstrap file if it is configured in the package
This method is called by the framework when packages are loaded.

The framework uses the following getter and setter methods to complete the package information.

MethodPurpose
addDependency(string $dependency)Add a dependency package
getDependencies(): arrayGet the names of the dependency packages
addFrontend(string $source)Add a frontend source
getFrontends(): arrayGet the frontend sources registered for the package
setBootstrap(string $bootstrap)Set the bootstrap file
setRouting(string $routing)Set the routing file
getRouting(): ?FileGet the routing file
getRoutingRules(): arrayGet the routes defined in the routing.json file
getConfigFile(): FileGet the package's configuration file (package.json)

Accessing a Package

In the packages\base\Package class, the fromName method is defined for accessing a project's packages. In addition to fromName, you can also access a project's packages by calling the package method defined in the packages\base\Packages class. For convenience, both fromName and package are defined as static methods.

If the specified package exists, the return value of fromName and package is an object of the packages\base\Package class that contains the package's details—such as its dependencies, routing file, and translation files—and, in general, all the settings configured in the package structure file (package.json).

If the specified package does not exist, a packages\base\IO\NotFoundException exception is thrown.

Accessing a package via the package method:

use packages\base\Packages;


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

Accessing a package via the fromName method:

use packages\base\Package;


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

File Paths and URLs

Two methods, getFilePath and url, are defined for accessing file addresses. Both methods take the file's path and name as a string input. The specified file does not need to exist.

If the second argument of the url method is set to true, it returns the full address (as a URL). The default value of this argument is false.

Difference between getFilePath and url

The getFilePath method is used to get a file's path inside the package, while the url method is used to get the file's internet (web) address.

Example 1:

controllers/Albums.php
<?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;
}
}

In the example above, we first build the file's storage path in $path, then pass $path to the getFilePath method so that the exact file path for the desired package is generated.

The output of the getFilePath method is as follows:

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

For more information about files and directories, refer to the Files and Directories pages.

Example 2:

controllers/Albums.php
<?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;
}
}

In the example above, we intend to give the user a file to download. First, we obtain an object of the File class corresponding to the received path and check whether the file exists.

info

For more information, refer to the Response page.

Example 3: Using the url method in a theme

views/profile/edit.php
<?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>

Reading File Contents

The getFileContents method is defined for reading a file's contents. This method takes the path and name of a file within the package as a string argument. If the file does not exist, a packages\base\IO\NotFoundException exception is thrown.

Example:

controllers/Main.php
<?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;
}
}

In the example above, the file's contents are obtained with the getFileContents method and passed to the View via the setData method.

Getting a File

The getFile method takes the file's path and name as a string, and its return value is an object of the File class. The specified file does not need to exist.

Example:

controllers/Main.php
<?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;
}
}

In the example above, the desired file is obtained by calling the getFile method, and then the existence of its parent directory is ensured (if the parent directory does not exist, it is created by calling the make method). Next, the text received from the input is written to the file. If the file does not exist, it is created by calling the write method and the text is written into it. If the file already exists, the new text replaces the previous content.

Adding New Options

In addition to the routing, frontend, autoload, ... keys that are defined in the package structure file and must be set, the framework allows programmers to add their own options to the package structure file and use them during the program's execution.

For example, the programmer sets the storage path for uploaded files in this file, and in the program—instead of using a static path—calls the package's option.

The getOption method is defined for retrieving options. The method's input argument is the option's key.

In addition to declaring options in the structure file, you can set the desired option during the program's execution using the setOption method; however, note that this option must be set before it is retrieved and used.

note

With this approach, the option is not persisted and is only accessible until the end of that same request.

Sample configuration file:

package.json
{
"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/"
}

Example: How to use options

controllers/Users.php
<?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;
}
}

The Bootstrap File

The framework defines a key named bootstrap. In this key, you specify the path to a PHP file, and after loading the package and before finding the routes and controllers, the framework calls and executes this file. This file is used to perform operations—such as checking the user's IP—that must be done before the application runs.

The framework automatically handles registering and calling the bootstrap file using the setBootstrap and bootup methods.

Declaring the bootstrap file in the package.json file:

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"
}

Sample bootstrap file:

bootstraps/checkAccess.php
<?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();
}