October: OctoberCMS Builder plugin, uploading file and storing in database

Created on 21 Oct 2016  路  14Comments  路  Source: octobercms/october

I am new to OctoberCMS and i am trying to create one plugin using builder plugin itself which OctoberCMS provides OctoberCMS Builder Plugin called something like "Social Links", everything working fine expect i am unable to understand the logic of uploading file to any directory and storing that name to my database table's particular field. My table's field name is "social_logo" in which i am trying to store the file name which will be uploaded.

I am able to upload file to default directory at the moment whichever OctoberCMS generating with the file i am uploading. But the thing is i am unable to store that particular file name to my database table's field.

Can someone guide me what should i do to achieve this ?

Here is the my model file what i have done so far.

SocialLinks.php

<?php

             namespace Technobrave\SocialLinks\Models;

              use Model;

             /**

                         Model */ class Sociallink extends Model { use \October\Rain\Database\Traits\Validation;

             /*
             Validation */ public $rules = [ ];

    /*
        Disable timestamps by default.
        Remove this line if timestamps are defined in the database table. */ public $timestamps = false;

    /**
        @var string The database table used by the model. */ public $table = 'technobravesociallinks';

    public $attachOne = [ 'social_logo' => 'System\Models\File' ];

           }

Fields.yaml

fields:
           social_logo:
    label: 'technobrave.sociallinks::lang.Sociallink.social_logo'
    span: auto
    oc.commentPosition: ''
    mode: file
    useCaption: true
    thumbOptions:
        mode: crop
        extension: auto
    type: fileupload

columns.yaml

columns:
social_logo:
    label: 'technobrave.sociallinks::lang.Sociallink.social_logo'
    type: text
    searchable: true
    sortable: true

As you can see on above code, for now i have only 1 field because i am having issues with this particular field only while uploading an image, i want to store that file name . All other form attributes working for me like text,textarea etc so for now i m only trying to achieve this thing with this single field.

Can someone guide me what should i do to solve this ?

Thanks

Most helpful comment

Don't know if you understand me or I'm not expressing myself correctly since english it's not my native language, I'll try again:

  • The attachOne declaration it's enough to upload your file and link it with your model. BUT its data it's stored in ANOTHER table in your database called system_files where it also stores the link to your model. So, you do not need to have a column in your database in order to store file data, because it already exists and it's handled automatically.

To get that data you only have to load a model object and access that file like:

$loadedModel->imageName;

That will return you a file object with all the data you need.

  • How to access the url of that file if it's an image? Just use:

$loadedModel->imageName->getPath();

I'll put an example of what you should need in your public pages:

  • Make a page
  • In the code section add:

(and keep in mind that all names and variables are random, don't exist, they are examples)

use Whatever\Name\Models\Model;


function onStart()
{
    $this['model_data'] = Model::first();
}
  • Ok, so, in your html section you'll only have to add a call to that model_data.
<img src="{{ model_data.yourFileName.getPath() }}" />

And that will make a page that shows an image in your frontend. I have checked it (with my model names and file names, of course, not this ones) and it works perfectly.

In your case it should be something like

<img src="{{ yourModelObject.social_logo.getPath() }}" />

I hope it's clear 8D

All 14 comments

Edit: why do you want to store the file name in your table? It seems to me you want to do something that is already implemented in october cms.

I don't see why you whould need to store that data in your table, when it's already stored and linked to your rows.

To access your files you only have to call the attached file as a method.

For example, having a attachOne called image I'd call it with $model->image(). That will return the FileModel loaded with all the data you could need.

Now. If you really really need to put that file name in your table, you can use a event listener, in this case, the saved one will do, since it is thrown each time a model stores data in your database.

        Sociallink::saved(
            function($model){
               1 - check you have uploaded a new file
               2 - if so, change the attribute of the model to the new filename
               3 - save again, since you are checking a new file upload, in step 1 you shouldn't have recursivity problems.

               To get the file data :
               // Maaaaaaaybe camelcase? 
                // Haven't checked and never did a file with "_" in the name. Sorry
                $file = $model->socialLogo();
            }
        );

With that you should be ok. You can add this listener to your construct, or your plugin boot, or whatever you want.

Would you like to know more?
Check the file attachments!

Well the reason i want to store file name is to diplay on front end. How can i display on front end.
I want to show this uploaded image as an image tag.
And my database field at the moment showing NULL data . is it what octobercms follows ? coz i have to create field to upload files, isnt it so will it be fine if it stores null data for each row ?

Also how can i show this attached file in my cms page using this component ?

Ok, if you want to upload and show the file you must use a file upload of image type. Then, october cms will do everything for you.

You only have to change your Fields.yaml social_logo into this:

fields:
social_logo:
            label: 'technobrave.sociallinks::lang.Sociallink.social_logo'
            mode: image
            type: fileupload

Then you will see the image file uploaded.

thumbOptions, useCaption are not useful there because they have the same value as the default one.

About the oc.commentPosition don't know why you are using it or where did you get it, but it's a private property from the plugin builder and you can't define it in your yamls since it gets its value from the commentPosition and comment options.

tl;dr: change the mode from your yaml from file to image and it will do what you want.

ok .. i have updated my fields.yaml file .. this is how my .yaml look like now ..

fields:
    social_logo:
        label: 'Social Logo'
        span: auto
        oc.commentPosition: ''
        mode: image
        useCaption: true
        thumbOptions:
            mode: crop
            extension: auto
        type: fileupload

Can you guide me how can i show now in my any of the front page which will be CMS page ofcourse ..
This is my test file code for now

test_cms_page

now how can show my image at front page ?

And FYI, i m having NULL values in my database table as soon as i upload any image however i m able to upload images in random directories ..

social_links_table
social_links_crud_list
social_links_file_upload_page

Now can you guide me how can i show the image in front end by using component code here ..

test_cms_page
social_links_test_page_inner_code

And this is how my test front end look like at the moment...

test_front_page

  • Still don't know why you are using oc.commentPosition: '' in your yaml. Is something that works? What I see in the code it's that is a private var from php, but I can be wrong.
  • October cms has its own table for storing the file data, system_files I think. So, you won't have any value on your tables, that's correct.
  • You have to use $model->fileName() and whatever you need (filename or whatev.). How to work with dynamic pages, example of how to use images and files.

tl;dr: jokingly, RTFM

Thanks for reply.

How can i use $model->fileName() in my current code ? do i need to add in my test cms file ? or in my model file ? can u give me some hint or sample code please based on above screenshots i have provided.

To learn how to use in your public code models, you should read the dynamic pages link I have sent you, about what to do to see images from a file, it's explained in the example of how to use images and files at the bottom of the page, sorry if I don't write you exact examples, but they are pretty nicely explained in the manual, though.

yes .. i have seen those links and gone through with those but i have already a for loop in my component code which is getting generated by builder plugin and m using one of my created plugin .. so i m bit confused how to utilize the code given in the sample document .. here is how my code looks like which is already having for loop ..

{% set records = builderList.records %}
{% set displayColumn = builderList.displayColumn %}
{% set noRecordsMessage = builderList.noRecordsMessage %}
{% set detailsPage = builderList.detailsPage %}
{% set detailsKeyColumn = builderList.detailsKeyColumn %}
{% set detailsUrlParameter = builderList.detailsUrlParameter %}

<ul class="record-list">
    {% for record in records %}
        <li>
            {# Use spaceless tag to remove spaces inside the A tag. #}
            {% spaceless %}
                {% if detailsPage %}
                    <a href="{{ detailsPage|page({ (detailsUrlParameter): attribute(record, detailsKeyColumn) }) }}">
                {% endif %}

                {{ attribute(record, displayColumn) }}

                {% if detailsPage %}
                    </a>
                {% endif %}
            {% endspaceless %}
        </li>
    {% else %}
        <li class="no-data">{{ noRecordsMessage }}</li>
    {% endfor %}
</ul>

{% if records.lastPage > 1 %}
    <ul class="pagination">
        {% if records.currentPage > 1 %}
            <li><a href="{{ this.page.baseFileName|page({ (pageParam): (records.currentPage-1) }) }}">&larr; Prev</a></li>
        {% endif %}

        {% for page in 1..records.lastPage %}
            <li class="{{ records.currentPage == page ? 'active' : null }}">
                <a href="{{ this.page.baseFileName|page({ (pageParam): page }) }}">{{ page }}</a>
            </li>
        {% endfor %}

        {% if records.lastPage > records.currentPage %}
            <li><a href="{{ this.page.baseFileName|page({ (pageParam): (records.currentPage+1) }) }}">Next &rarr;</a></li>
        {% endif %}
    </ul>
{% endif %}

As you can see this code...

<ul class="record-list">
    {% for record in records %}
        <li>
            {# Use spaceless tag to remove spaces inside the A tag. #}
            {% spaceless %}
                {% if detailsPage %}
                    <a href="{{ detailsPage|page({ (detailsUrlParameter): attribute(record, detailsKeyColumn) }) }}">
                {% endif %}

                {{ attribute(record, displayColumn) }}

                {% if detailsPage %}
                    </a>
                {% endif %}
            {% endspaceless %}
        </li>
    {% else %}
        <li class="no-data">{{ noRecordsMessage }}</li>
    {% endfor %}
</ul>

So i m confused how to show image here ?

Addionally, in my mode i already have this code ..

 public $attachOne = [
            'social_logo' => 'System\Models\File'
    ];

but when i m trying to add this code...

$model->social_logo = Input::file('social_logo');

i m having error saying syntax error, unexpected '$model' (T_VARIABLE), expecting function (T_FUNCTION) i know i m making mistake here but in doc that is what they are saying .. can u show me a way to add this feature as well as in front page loop how to show an image ? that will be very helpful for me..

Don't know if you understand me or I'm not expressing myself correctly since english it's not my native language, I'll try again:

  • The attachOne declaration it's enough to upload your file and link it with your model. BUT its data it's stored in ANOTHER table in your database called system_files where it also stores the link to your model. So, you do not need to have a column in your database in order to store file data, because it already exists and it's handled automatically.

To get that data you only have to load a model object and access that file like:

$loadedModel->imageName;

That will return you a file object with all the data you need.

  • How to access the url of that file if it's an image? Just use:

$loadedModel->imageName->getPath();

I'll put an example of what you should need in your public pages:

  • Make a page
  • In the code section add:

(and keep in mind that all names and variables are random, don't exist, they are examples)

use Whatever\Name\Models\Model;


function onStart()
{
    $this['model_data'] = Model::first();
}
  • Ok, so, in your html section you'll only have to add a call to that model_data.
<img src="{{ model_data.yourFileName.getPath() }}" />

And that will make a page that shows an image in your frontend. I have checked it (with my model names and file names, of course, not this ones) and it works perfectly.

In your case it should be something like

<img src="{{ yourModelObject.social_logo.getPath() }}" />

I hope it's clear 8D

Excellent one .. this is the answer i wanted .. i removed the field from Database table called "social_logo" then simply put this code in my model

public $attachOne = [
            'social_logo' => 'System\Models\File'
    ];

Then created a test cms page template and inside 'code''s section, i have put this code

use technobrave\sociallinks\Models\Sociallink;

function onStart()
{
    $this['model_data'] = Sociallink::first();
}

and in html markup i have simply put this

<img src="{{ model_data.social_logo.getPath() }}" />

and whoa .. its done .. thanks for support. great work ..

You are welcome 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dunets picture dunets  路  3Comments

m49n picture m49n  路  3Comments

mittultechnobrave picture mittultechnobrave  路  3Comments

sozonovalexey picture sozonovalexey  路  3Comments

EbashuOnHolidays picture EbashuOnHolidays  路  3Comments