Images

All images in the system are saved in the images db table. The images table has the following structure:

    'item_id' => bigint
    'path'    => varchar(255) 
    'name'    => varchar(255) 
    'type'    => tinyint

item_id field is the ID of the item (article, pdf, ad, magazine, etc) for which the image is saved.
path is the relative path of the image file on the filesystem, without the filename itself
name is the filename of that image on filesystem
type field is number and describes the type of the image. With this type we can correctly query the item to which the image belongs. Currently we have the following image types defined in config/images.php.

	'types' => [
		'pages' 	=> 1, // PDF pages as images
		'extracted' => 2, // Images extracted from PDF
		'cropped' 	=> 3, // Images cropped from PDF
		'magazine' 	=> 4, // Magazine cover image
		'article' 	=> 5, // Main image of the Article
		'hubpage' 	=> 6, // HubPage image of the Article
		'ad' 		=> 7, // Ad image
		'icon' 		=> 8, // Category icon
		'image' 	=> 9, // Category image
		'product_logo' => 10
	]

So for example if an image have a type of 7 then we know the item_id is an ID of an ad record from the ads table.

Image Model

To make work with images easier we have an Image model located in app/Models/Image.php which we’re using for faster link generation and so on. There is 2 main methods that we’re using from this model:

// App\Models\Image
    public function getUrl() {
        if ($this->name && $this->path) {
            return config("app.media_url").$this->path.'/'.$this->name;
        } else {
            return false; 
        }
    }

    public static function getUrlStatic($id) {
		if (null !== $image = Image::find($id)) {
			return $image->getUrl();
		}
    }

Querying images

Most of the time the image relations are defined inside each models that requires using images and there can be more then one: Some relations from the different models:

// App\Models\Articles
public function hubpageImage() {
    return $this->belongsTo(Image::class, 'hubpage_image_id');
}

// App\Models\Magazine
public function hubpageImage() {
    return $this->belongsTo(Image::class, 'hubpage_image_id');
}

// App\Models\Magazine
public function printheaderImage() {
    return $this->belongsTo(Image::class, 'printheader_image_id');
}
// App\Models\Magazine
public function logoImage() {
    return $this->belongsTo(Image::class, 'logo_image_id');
}

So everytime we need the image to be fetched for a given record we can eager load it with Eloquent query.

$article = Article::where('field', 'value')->with('hubpageImage')->first()
$article->hubpageImage->getUrl()

$magazine = Magazine::where('field', 'value')->with('printHeaderImage')->first();
$magazine->printHeaderImage->getUrl()

In case where we have an ID of an image, but we don’t work with an instance of a model (lets say we’re working with array structure) then we’re using the static method from the Image model to get the url of the image:

$imgUrl = \App\Models\Image::getUrlStatic($article['hubpage_image_id]);

Saving an image

There’s two ways to save an image in the system. Either from the helper function imageStore() or via a model’s method (which uses imageStore internaly).

The imageStore function accepts either a url of an image, base64 string or FILE_TMP descriptor. It will fetch the image and save it on the filesystem and return an object with the following structure:

        return (object) [
            'path' => $path,
            'name' => $name,
            'src' => asset($path . '/' . $name)
        ];

We can then use this object to save the image data in the datbase.

Each model that uses images has a dedicated method most of the time to make the saving of an image easy and quick. For example when we want to save an uploaded image as an article hubpage image we’re using the setHubpageImage() method from the article, which will:

  1. cal the imageStore function,
  2. get the result,
  3. save it in the DB with correct type and type_id data and assign that ID to the hubpage_image_id field in the article table.

We have such methods for Magazine,Category,Article models etc.

    /**
     * Set the Hubpage image for the Article.
     *
     * @param resource $image
     */
    public function setHubpageImage($image) {
        $image = imageStore($image);
        $image = Image::create([
                    'item_id' => $this->id,
                    'path' => $image->path,
                    'name' => $image->name,
                    'type' => Image::getType('hubpage')
        ]);

        $this->hubpage_image_id = $image->id;
        $this->save();
    }

Thumbnails and Resized Images

Every model that has images to it (Article, Magazine, etc) has methods for accessing the thumbnails or resized versions of the uploaded images.


    // Magazine
	public function getBlurredImageUrl()
	{
		return createImageUrl($this->getImageUrl(), 'trmblurred', 'thumbnail');
	}

	public function getThumbnailUrl()
	{
		return createImageUrl($this->getImageUrl(), 'trmresize', 'thumbnail');
	}

    // Article
    public function getBlurredImageUrl() {

        $hubpageImage = $this->hubpageImage ? $this->hubpageImage : false;
        if ($this->layout_id == 0) {
            return $hubpageImage
                ? createImageUrl($hubpageImage->getUrl(), 'trmblurred', 'thumbnail')
                : null;

        } else if ($this->layout_id == 1) {

            return (
                $hubpageImage
                    ? $hubpageImage->getUrl()
                    : $this->setGoogleMapImageUrl()
            ) ."?ver=".md5(rand(1000,99999));
        }
    ...
    }
    public function getThumbnailUrl() {
        if ($this->layout_id == 0) {
            return $this->hubpageImage ? createImageUrl($this->hubpageImage->getUrl(), 'trmresize', 'thumbnail') : null;
        } else if ($this->layout_id == 1) {
            return ($this->hubpage_image_id ? $this->hubpageImage->getUrl() : $this->setGoogleMapImageUrl()) ."?ver=".md5(rand(1000,99999));
        }
        ...
    }    

All of these methods are using the createImageUrl() function internally which is defined in the functions.php file. This createImageUrl function is responsible for building the correct url for resized/blurred/thumbnailed version of the uploaded image. This url is processed by the app/Http/Controllers/ImagesServer.php controller class. The route is defined in domains_web_basic.php route file

Route::get('image_process/{image}', 'App\Http\Controllers\ImagesServer@process')->where('image', '.*');

Also this routing is declared on nginx level. So you might want to look around the nginx config files for more details.

After the request is passed to the application we try to locate the integration from which is made (via the url). Also the url contains information about what kind if image we want (blurred, resized only, etc) and then checks if this type of image has a predefined dimensions for that integrations. Dimensions are also depending on the device type from which the request is made and the device type is being determined by the nginx server through the user agent header in the request. If no predefined dimension is available for the given integration, image type and device, then the required dimensions are taken from the config/imagesServer.php config file. After that this iformation is passed to the app/Helpers/SimpleImage.php class, which is the class responsible for cropping and creating images in the system. NOTE: Before calling the SimpleImage class the scripts will check if the given request already corresponds to a file on the filesystem and if so, then this image will be returned.