Codeigniter method of class - undefiend function - codeigniter

ive try to do my first steps with codeignitter, so i have write a new methode(function) in a existing class.
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class App
{
/**
* Options autoload=1
* #var array
*/
private $options = [];
/**
* Quick actions create aside
* #var array
*/
private $quick_actions = [];
/**
* CI Instance
* #deprecated 1.9.8 Use $this->ci instead
* #var object
*/
private $_instance;
/**
* CI Instance
* #var object
*/
private $ci;
/**
* Show or hide setup menu
* #var boolean
*/
private $show_setup_menu = true;
/**
* Available reminders
* #var array
*/
private $available_reminders = ['customer', 'lead', 'estimate', 'invoice', 'proposal', 'expense', 'credit_note'];
/**
* Tables where currency id is used
* #var array
*/
private $tables_with_currency = [];
/**
* Media folder
* #var string
*/
private $media_folder;
/**
* Available languages
* #var array
*/
private $available_languages = [];
public function __construct()
{
$this->ci = & get_instance();
// #deprecated
$this->_instance = $this->ci;
$this->init();
do_action('app_base_after_construct_action');
}
/**
* Check if database upgrade is required
* #param string $v
* #return boolean
*/
public function is_db_upgrade_required($v = '')
{
if (!is_numeric($v)) {
$v = $this->get_current_db_version();
}
$this->ci->load->config('migration');
if ((int) $this->ci->config->item('migration_version') !== (int) $v) {
return true;
}
return false;
}
/**
* Return current database version
* #return string
*/
public function get_current_db_version()
{
$this->ci->db->limit(1);
return $this->ci->db->get('tblmigrations')->row()->version;
}
/**
* Upgrade database
* #return mixed
*/
public function upgrade_database()
{
if (!is_really_writable(APPPATH . 'config/config.php')) {
show_error('/config/config.php file is not writable. You need to change the permissions to 755. This error occurs while trying to update database to latest version.');
die;
}
$update = $this->upgrade_database_silent();
if ($update['success'] == false) {
show_error($update['message']);
} else {
set_alert('success', 'Your database is up to date');
if (is_staff_logged_in()) {
redirect(admin_url(), 'refresh');
} else {
redirect(site_url('authentication/admin'));
}
}
}
/**
* Make request to server to get latest version info
* #return mixed
*/
public function get_update_info()
{
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_USERAGENT => $this->ci->agent->agent_string(),
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_TIMEOUT => 30,
CURLOPT_URL => UPDATE_INFO_URL,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => [
'update_info' => 'true',
'current_version' => $this->get_current_db_version(),
],
]);
$result = curl_exec($curl);
$error = '';
if (!$curl || !$result) {
$error = 'Curl Error - Contact your hosting provider with the following error as reference: Error: "' . curl_error($curl) . '" - Code: ' . curl_errno($curl);
}
curl_close($curl);
if ($error != '') {
return $error;
}
return $result;
}
/**
* Return all available languages in the application/language folder
* #return array
*/
public function get_available_languages()
{
$languages = $this->available_languages;
return do_action('before_get_languages', $languages);
}
/**
* Function that will parse table data from the tables folder for amin area
* #param string $table table filename
* #param array $params additional params
* #return void
*/
public function get_table_data($table, $params = [])
{
$hook_data = do_action('before_render_table_data', [
'table' => $table,
'params' => $params,
]);
foreach ($hook_data['params'] as $key => $val) {
$$key = $val;
}
$table = $hook_data['table'];
$customFieldsColumns = [];
$path = VIEWPATH . 'admin/tables/' . $table . '.php';
if (file_exists(VIEWPATH . 'admin/tables/my_' . $table . '.php')) {
$path = VIEWPATH . 'admin/tables/my_' . $table . '.php';
}
include_once($path);
echo json_encode($output);
die;
}
/**
* Check if a option value is preset or individual
* #param string $name, string $value
* #return true/false
*/
public function option_is_preset($name,$value)
{
$str="`name`='".$name."' and value='".$value."' ";
$this->ci->db->select('id, name, value');
$this->ci->db->where($str);
$row = $this->ci->db->get('4U_tbloptions_preset')->row_array();
if ($row['id']>0) {
return true;
}
return false;
}
/**
* All available reminders keys for the features
* #return array
*/
public function get_available_reminders_keys()
{
return $this->available_reminders;
}
/**
* Get all db options
* #return array
*/
public function get_options()
{
return $this->options;
}
/**
* Function that gets option based on passed name
* #param string $name
* #return string
*/
public function get_option($name)
{
if ($name == 'number_padding_invoice_and_estimate') {
$name = 'number_padding_prefixes';
}
$val = '';
$name = trim($name);
if (!isset($this->options[$name])) {
// is not auto loaded
$this->ci->db->select('value');
$str="`name`='".$name."' and `maccid`='".$this->ci->session->userdata('macc_id')."'";
$this->ci->db->where($str);
$row = $this->ci->db->get('4U_accounts_tbloptions')->row();
if ($row) {
#echo"Wert aus account_tbloptions";
$val = $row->value;
}
} else {
#echo $name.'->'.$val.' Autoload - nicht aus DB!<br>';
$val = $this->options[$name];
}
$hook_data = do_action('get_option', ['name' => $name, 'value' => $val]);
//Fallback auf Standardwert
if ($hook_data['value']=='')
{
$this->ci->db->select('value');
$this->ci->db->where('name', $name);
$row = $this->ci->db->get('4U_tbloptions_preset')->row();
if ($row) {
#echo"Wert aus preset";
$val = $row->value;
}
$hook_data = do_action('get_option', ['name' => $name, 'value' => $val]);
}
return $hook_data['value'];
}
/**
* Add new quick action data
* #param array $item
*/
public function add_quick_actions_link($item = [])
{
$this->quick_actions[] = $item;
}
/**
* Quick actions data set from admin_controller.php
* #return array
*/
public function get_quick_actions_links()
{
$this->quick_actions = do_action('before_build_quick_actions_links', $this->quick_actions);
return $this->quick_actions;
}
/**
* Aside.php will set the menu visibility here based on few conditions
* #param int $total_setup_menu_items total setup menu items shown to the user
*/
public function set_setup_menu_visibility($total_setup_menu_items)
{
$this->show_setup_menu = $total_setup_menu_items == 0 ? false : true;
}
/**
* Check if should the script show the setup menu or not
* #return boolean
*/
public function show_setup_menu()
{
return do_action('show_setup_menu', $this->show_setup_menu);
}
/**
* Return tables that currency id is used
* #return array
*/
public function get_tables_with_currency()
{
return do_action('tables_with_currency', $this->tables_with_currency);
}
/**
* Return the media folder name
* #return string
*/
public function get_media_folder()
{
return do_action('get_media_folder', $this->media_folder);
}
/**
* Upgrade database without throwing any errors
* #return mixed
*/
private function upgrade_database_silent()
{
$this->ci->load->config('migration');
$beforeUpdateVersion = $this->get_current_db_version();
$this->ci->load->library('migration', [
'migration_enabled' => true,
'migration_type' => $this->ci->config->item('migration_type'),
'migration_table' => $this->ci->config->item('migration_table'),
'migration_auto_latest' => $this->ci->config->item('migration_auto_latest'),
'migration_version' => $this->ci->config->item('migration_version'),
'migration_path' => $this->ci->config->item('migration_path'),
]);
if ($this->ci->migration->current() === false) {
return [
'success' => false,
'message' => $this->ci->migration->error_string(),
];
}
update_option('upgraded_from_version', $beforeUpdateVersion);
return [
'success' => true,
];
}
/**
* Init necessary data
*/
protected function init()
{
//Autoloadfelder zuerst alle Presetfelder, die dann mit den Individualfeldern ueberschrieben werden
$optionsA = $this->ci->db->select('name, value')
->where('autoload', 1)
->get('4U_tbloptions_preset')->result_array();
$str=" 'maccid'='".$this->ci->session->userdata('macc_id')."' AND 'autoload'='1' ";
$optionsB = $this->ci->db->select('name, value')
->where($str)
->get('4U_accounts_tbloptions')->result_array();
$options=array_merge($optionsA, $optionsB);
// Loop the options and store them in a array to prevent fetching again and again from database
foreach ($options as $option) {
$this->options[$option['name']] = $option['value'];
}
/**
* Available languages
*/
foreach (list_folders(APPPATH . 'language') as $language) {
if (is_dir(APPPATH . 'language/' . $language)) {
array_push($this->available_languages, $language);
}
}
/**
* Media folder
* #var string
*/
$this->media_folder = do_action('before_set_media_folder', 'media');
/**
* Tables with currency
* #var array
*/
$this->tables_with_currency = [
[
'table' => 'tblinvoices',
'field' => 'currency',
],
[
'table' => 'tblexpenses',
'field' => 'currency',
],
[
'table' => 'tblproposals',
'field' => 'currency',
],
[
'table' => 'tblestimates',
'field' => 'currency',
],
[
'table' => 'tblclients',
'field' => 'default_currency',
],
[
'table' => 'tblcreditnotes',
'field' => 'currency',
],
[
'table' => 'tblsubscriptions',
'field' => 'currency',
],
];
}
/**
* Predefined contact permission
* #deprecated 1.9.8 use get_contact_permissions() instead
* #return array
*/
public function get_contact_permissions()
{
return get_contact_permissions();
}
}
Now i want to use this methode for example like this
echo"Test1: ".get_option('company_logo_dark');
echo"Test2: ".option_is_preset('company_logo_dark');
The methode "get_option" is one of the existing methode in the class.
This (get_option) work, but option_is_present produce a error " Call to undefined function option_is_preset() "
If i try
echo "Test3: ".$this->app->option_is_preset('company_logo',$company_logo);
it will work.
Why the first methode "get_option" i can use in this way ( echo "Test: ".get_option(string); " and why i can't do the same way for the other methode?
Thanks a lot for support me :-)

Inside class, you need to use the pseudo-variable $this
echo"Test1: ". $this->get_option('company_logo_dark');
echo"Test2: ". $this->option_is_preset('company_logo_dark', 'some_value');
Unsing a instance of a class:
$instance = new App();
echo"Test1: ". $instance ->get_option('company_logo_dark');
echo"Test2: ". $instance ->option_is_preset('company_logo_dark', 'some_value');
If the class App is placed in the library directory, you can use the Codeigniter Loader Class
$this->load->library('app');
echo"Test1: ". $this->app->get_option('company_logo_dark');
echo"Test2: ". $this->app->option_is_preset('company_logo_dark', 'some_value');
EDIT 1
get_option method can be called directly only if this is declared outside class. Please see the next example
function method_a($var) {
echo __METHOD__ . ' : ' . $var .'<br />';
}
class MyClass {
public function method_a($var) {
echo __METHOD__ . ' : ' . $var .'<br />';
$this->method_b($var);
}
public function method_b($var) {
echo __METHOD__ . ' : ' . $var .'<br />';
}
}
$instance = new MyClass();
$instance->method_a("Test");
method_a("Test");
this will return:
MyClass::method_a : Test
MyClass::method_b : Test
method_a : Test
EDIT 2
According to the updated class, method option_is_preset takes two arguments, $name and $value and you are trying to call only with one argument
echo"Test2: ".option_is_preset('company_logo_dark'); // wrong
echo"Test2: ".option_is_preset('company_logo_dark', 'some_value'); // correct

In another file i've found that
function get_option($name)
{
$CI = & get_instance();
if (!class_exists('app')) {
$CI->load->library('app');
}
return $CI->app->get_option($name);
}
This explains, why it is possible to call the "get_option" in a normal way of a function.
So i've add
function option_is_preset($name, $value)
{
$CI = & get_instance();
if (!class_exists('app')) {
$CI->load->library('app');
}
return $CI->app->option_is_preset($name, $value);
}
and now i can call the new methode like a function :-))

Related

Why do I get a dirty response from my Laravel API using GuzzleHttp?

In my API, my controllers extend from BaseController and my endpoints send responses using the sendResponse method (this is my BaseController):
class BaseController extends Controller
{
/**
* success response method.
*
* #param mixed $data The data resulting from the transaction
* #param string $message The success message of the transaction
* #param int $status The error code of the transaction, default is 200
*
* #return JsonResponse
*/
public function sendResponse( $data, string $message, int $status = 200 ) : JsonResponse
{
$response = [
'success' => true,
'data' => $data,
'message' => $message,
];
return response()->json( $response, $status );
}
/**
* return error response.
*
* #param string $message The error message
* #param mixed $data The list of errors of the transaction
* #param int $status The error code of the transaction, default is 404
*
* #return JsonResponse
*/
public function sendError( string $message, array $data = [], int $status = 404 ) : JsonResponse
{
$response = [
'success' => false,
'message' => $message,
];
if( !empty( $data ) ){
$response[ 'data' ] = $data;
}
return response()->json( $response, $status );
}
}
For example I can do this:
/**
* Display a listing of the resource.
*
* #return JsonResponse
*/
public function index() : JsonResponse
{
$users = User::all();
return $this->sendResponse( UserResource::collection( $users ), 'success' );
}
Now, in the other side, I have a project that consumes the API using Guzzle, so I have created a class that handles the requests:
namespace App\Models;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Psr\Http\Message\ResponseInterface;
class RequestURL
{
public string $endpoint;
public string $method;
public array $params;
public array $headers;
public mixed $response = null;
/**
* Constructor of the class
*
* #param string $endpoint
* #param string $method
* #param array $params
* #param array $headers
*/
public function __construct( string $endpoint, string $method = 'post', array $params = [], array $headers = [] )
{
$this->endpoint = $endpoint;
$this->method = $method;
$this->params = $params;
$this->headers = $this->makeHeaders( $headers );
$this->send();
}
/**
* Sends the request and expects the response from the api endpoint
*
* #return void
*/
private function send() : void
{
$client = new Client( [ 'base_uri' => config( 'superveci.api' ) ] );
try{
$this->response = $client->request( $this->method, $this->endpoint, [
'json' => $this->params,
'headers' => $this->headers,
'verify' => false,
] );
}
catch( GuzzleException $e ){
// TODO : log the error request
}
}
/**
* Returns the response on the requested url
*
* #return ResponseInterface|null
*/
public function getResponse() : ?ResponseInterface
{
return $this->response;
}
/**
* Returns the body of the response as a json object
*
* #return mixed
*/
public function getBody() : mixed
{
if( isset( $this->response ) ){
return json_decode( substr( (string) $this->getResponse()->getBody()->getContents(), 39 ) );
}
return null;
}
/**
* Returns the data from the response as a json object
*
* #return mixed
*/
public function getData() : mixed
{
return data_get( $this->getBody(), 'data' );
}
/**
* #return int
*/
public function getCode() : int
{
if( $this->response != null ){
return $this->response->getStatusCode();
}
return 401;
}
/**
* Sets the headers of the request up
*
* #param array $headers
*
* #return array
*/
private function makeHeaders( array $headers = [] ) : array
{
$bearer = ( isset( $headers[ 'token' ] ) ) ? $headers[ 'token' ] : request()->cookie( '_token' );
if( $bearer != null ){
$headers[ 'Authorization' ] = 'Bearer ' . $bearer;
}
return array_merge( [ 'Accept' => 'application/json', ], $headers );
}
}
As you can see, in the getBody() method, I wanted to cast the response data as an object, so, the logical thing here was to use json_decode. But for some reason it was returning null, until I found out that the response was dirty and I had to clean the first 39 characters of it, to be able to cast it using:
substr( (string) $this->getResponse()->getBody()->getContents(), 39 )
If I don' t do it, the response I get is similar to this (this is the resulting inspected code from my browser):
<pre hidden="">
{"success":true,"data":{"saludo":"Hello world","despedida":"Good bye cruel world"},"message":"success"}
</pre>
And of course the json_decode fails.
What is going on? Is this normal behavior? will it always be 39 characters?
Thanks

How to get file extension from SwiftAttachment object in Laravel Email Transport

This is Laravel 8. I'm extending Illuminate\Mail\Transport\Transport class to create a custom mail transport in order to utilize the company's custom mail API with Illuminate\Mail\Mailable. I got most of it working, including file attachments, however the Swift_Mime_SimpleMimeEntity and the classes deriving from it contain getBody(), getFilename(), getSize(), and getContentType() but no methods to extract file extension.
<?php
namespace App\CustomMailDriver;
use GuzzleHttp\ClientInterface;
use Illuminate\Mail\Transport\Transport;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Swift_Mime_SimpleMessage;
class CustomTransport extends Transport
{
/**
* Guzzle client instance.
*
* #var \GuzzleHttp\ClientInterface
*/
protected $client;
/**
* API key.
*
* #var string
*/
protected $key;
/**
* The API URL to which to POST emails.
*
* #var string
*/
protected $url;
/**
* Create a new Custom transport instance.
*
* #param \GuzzleHttp\ClientInterface $client
* #param string|null $url
* #param string $key
* #return void
*/
public function __construct(ClientInterface $client, string $url, string $key)
{
$this->key = $key;
$this->client = $client;
$this->url = $url;
}
/**
* {#inheritdoc}
*/
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
{
$this->beforeSendPerformed($message);
$payload = $this->getPayload($message);
try {
// ignore ssl (esp when working in DEV/QA)
$response = Http::withoutVerifying()->withHeaders([
'X-Authorization' => $this->key
])->post($this->url, $payload);
Log::info($response->body());
} catch (\Exception $e) {
Log::error($e->getMessage());
}
$this->sendPerformed($message);
return $this->numberOfRecipients($message);
}
/**
* Get the HTTP payload for sending the message.
*
* #param \Swift_Mime_SimpleMessage $message
* #return array
*/
protected function getPayload(Swift_Mime_SimpleMessage $message): array
{
// to
if (!empty($message->getTo())) {
$payload['payload']['to']['email'] = key($message->getTo());
}
// cc
if (!empty($message->getCc())) {
$payload['payload']['cc']['email'] = key($message->getCc());
}
// bcc
if (!empty($message->getBcc())) {
$payload['payload']['bcc']['email'] = key($message->getBcc());
}
// subject
$payload['payload']['subject'] = $message->getSubject();
// html
$payload['payload']['message']['html'] = $message->getBody();
// message children contains plain text, attachments, etc
$children = $message->getChildren();
if (!empty($children)) {
foreach($children as $child) {
// attachments
if (get_class($child) === 'Swift_Attachment') {
$payload['payload']['attachments'][] = [
'content' => base64_encode($child->getBody()),
'filename' => $child->getFilename(),
];
}
// plain text
if (get_class($child) === 'Swift_MimePart') {
$payload['payload']['message']['text'] = $child->getBody();
}
}
}
return $payload;
}
}
I had to go different route. Instead of searching the extension inside Transport class using Swift_Mime_SimpleMessage, I passed the filename with the original extension to Transport class from Illuminate\Mail\Mailable
public function build()
{
$tempUpload = request()->file('file_attachment');
$filename = $tampUpload->getClientOriginalName() . "." . $tempUpload->getClientOriginalExtension();
return $this->from($this->from_email, $this->from_name)
->subject('subject line')
->attach($tempUpload, ['as' => $filename)
->view('emails.gce.supplier_supplier')
->with($this->data);
}

Laravel : Overwrite Socialite Provider to add new fields

I want to extend/overwrite my LinkedInProvider.php (in vendor\laravel\socialite\src\Two) to add new fields in the Linkedin Request.
I've create a new LinkedInProvider.php (in app\Providers) with the following code :
namespace App\Providers;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Two\ProviderInterface;
use Laravel\Socialite\Two\User;
class LinkedInProvider extends AbstractProvider implements ProviderInterface
{
/**
* The scopes being requested.
*
* #var array
*/
protected $scopes = ['r_basicprofile', 'r_emailaddress'];
/**
* The separating character for the requested scopes.
*
* #var string
*/
protected $scopeSeparator = ' ';
/**
* The fields that are included in the profile.
*
* #var array
*/
protected $fields = [
'id', 'first-name', 'last-name', 'formatted-name',
'email-address', 'headline', 'location', 'industry', 'positions',
'public-profile-url', 'picture-url', 'picture-urls::(original)',
];
/**
* {#inheritdoc}
*/
protected function getAuthUrl($state)
{
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state);
}
/**
* {#inheritdoc}
*/
protected function getTokenUrl()
{
return 'https://www.linkedin.com/oauth/v2/accessToken';
}
/**
* Get the POST fields for the token request.
*
* #param string $code
* #return array
*/
protected function getTokenFields($code)
{
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
}
/**
* {#inheritdoc}
*/
protected function getUserByToken($token)
{
$fields = implode(',', $this->fields);
$url = 'https://api.linkedin.com/v1/people/~:('.$fields.')';
$response = $this->getHttpClient()->get($url, [
'headers' => [
'x-li-format' => 'json',
'Authorization' => 'Bearer '.$token,
],
]);
return json_decode($response->getBody(), true);
}
/**
* {#inheritdoc}
*/
protected function mapUserToObject(array $user)
{
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => null, 'name' => Arr::get($user, 'formattedName'),
'email' => Arr::get($user, 'emailAddress'), 'avatar' => Arr::get($user, 'pictureUrl'),
'avatar_original' => Arr::get($user, 'pictureUrls.values.0'),
]);
}
/**
* Set the user fields to request from LinkedIn.
*
* #param array $fields
* #return $this
*/
public function fields(array $fields)
{
$this->fields = $fields;
return $this;
}
}
But now, I've got this error :
Type error: Argument 1 passed to Laravel\Socialite\Two\AbstractProvider::__construct() must be an instance of Illuminate\Http\Request, instance of Illuminate\Foundation\Application given, called in G:\laragon\www\localhost\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRepository.php on line 201
I know I can install Socialite Manager, but I just want to overwrite the fields list to add new field (like position and industry)
You shouldn't have to overwrite/extend the whole class. In the Laravel\Socialite\Two\User object that is being created, there is a $user property, which contains the raw information the provider sent back.
When making the request, you can set the fields you want LinkedIn to return in your controller method:
public function redirectToProvider()
{
$fields = [
'id', 'first-name', 'last-name', 'formatted-name',
'email-address', 'headline', 'location', 'industry',
'public-profile-url', 'picture-url', 'picture-urls:(original)',
'positions', 'summary' // <-- additional fields here
];
return Socialite::driver('linkedin')->fields($fields)->redirect();
}
You can see two additional fields being requested, positions and summary, which aren't included by default.
Happy hacking!

Error uploading image in yii2(SyntaxError: Unexpected token < in JSON at position 0)

When i try to upload image i have got SyntaxError: Unexpected token < in JSON at position 0. The name of image saves in DB but image file(in web/uploads) doesn't. I don't know why. Help me please.
here is my cod from the view(update.php)
...
<div class="user-form">
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multi-part/form-data']]); ?>
<?= $form->field($model, 'email')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'usersurname')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'age')->textInput() ?>
<?= $form->field($model, 'img')->widget(FileInput::classname(), [
'options' => ['accept'=>'image/*'],
'pluginOptions'=>[
'uploadUrl' => Url::to(['/uploads']),
'allowedFileExtensions'=>['jpg', 'gif', 'png'],
'showUpload' => true,
'initialPreview' => [
// $model-> img ? Html::img($model-> img) : null, // checks the models to display the preview
],
'overwriteInitial' => false,
],
]); ?>
<div class="form-group">
<?= Html::submitButton(Yii::t('app', 'BUTTON_SAVE'), ['class' => 'btn siteColor']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
...
code from controller
...
public function actionUpdate()
{
$user = $this->findModel();
$model = new ProfileUpdateForm($user);
if ($model->load(Yii::$app->request->post()) && $model->update()) {
return $this->redirect(['index']);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
...
code from model
<?php
namespace app\modules\user\models;
use yii\base\Model;
use Yii;
class ProfileUpdateForm extends Model
{
public $email;
public $username;
public $usersurname;
public $data;
public $age;
public $from;
public $time;
public $img;
public $file;
/**
* #var User
*/
private $_user;
public function __construct(User $user, $config = [])
{
$this->_user = $user;
parent::__construct($config);
}
public function init()
{
$this->email = $this->_user->email;
$this->username = $this->_user->username;
$this->usersurname = $this->_user->usersurname;
$this->img = $this->_user->img;
// $this-> file = $this->_user-> file;
parent::init();
}
public function rules()
{
return [
['email', 'required'],
['email', 'email'],
[
'email',
'unique',
'targetClass' => User::className(),
'message' => Yii::t('app', 'ERROR_EMAIL_EXISTS'),
'filter' => ['<>', 'id', $this->_user->id],
],
[['email','usersurname', 'username', 'img'], 'string', 'max' => 255],
[['img'], 'file', 'extensions' => 'png, jpg, gif'],
['age', 'integer'],
];
}
public function update()
{
if ($this->validate()) {
$user = $this->_user;
$user->email = $this->email;
$user->username = $this->username;
$user-> age = $this -> age;
return $user->save();
} else {
return false;
}
}
}
You mean this? it's situated in the same directory with actionUpdate.
But how can i use it in the view(profile/update.php)? 'Coz i try to update the Image from the view(profile/update.php) and use actionUpdate. Maybe there have another ways to do it?
...
public function actionUpload()
{
$user = $this->findModel();
$model = new User($user);
if ($model->load(Yii::$app->request->post()) && $model->update()) {
$imageName = rand(1000,100000);
$model->file = UploadedFile::getInstance($model, 'file');
$model->img =''.$imageName.'.'.$model->file->extension; //тут возникает ошибка Trying to get property of non-object
$model->file->saveAs('uploads/'.$imageName.'.'.$model->file->extension);
$model->file = null;
$model->save();
return $this->redirect(['index']);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
...
QUESTION UPDATED
code from vendor/kartik-v/yii2-krajee-base/FileInput
<?php
/**
* #copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2016
* #package yii2-widgets
* #subpackage yii2-widget-fileinput
* #version 1.0.5
*/
namespace kartik\file;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use kartik\base\InputWidget;
use kartik\base\TranslationTrait;
/**
* Wrapper for the Bootstrap FileInput JQuery Plugin by Krajee. The FileInput widget is styled for Bootstrap 3.0 with
* ability to multiple file selection and preview, format button styles and inputs. Runs on all modern browsers
* supporting HTML5 File Inputs and File Processing API. For browser versions IE9 and below, this widget will
* gracefully degrade to normal HTML file input.
*
* #see http://plugins.krajee.com/bootstrap-fileinput
* #see https://github.com/kartik-v/bootstrap-fileinput
*
* #author Kartik Visweswaran <kartikv2#gmail.com>
* #since 2.0
* #see http://twitter.github.com/typeahead.js/examples
*/
class FileInput extends InputWidget
{
use TranslationTrait;
/**
* #var bool whether to resize images on client side
*/
public $resizeImages = false;
/**
* #var bool whether to load sortable plugin to rearrange initial preview images on client side
*/
public $sortThumbs = true;
/**
* #var bool whether to load dom purify plugin to purify HTML content in purfiy
*/
public $purifyHtml = true;
/**
* #var bool whether to show 'plugin unsupported' message for IE browser versions 9 & below
*/
public $showMessage = true;
/*
* #var array HTML attributes for the container for the warning
* message for browsers running IE9 and below.
*/
public $messageOptions = ['class' => 'alert alert-warning'];
/**
* #var array the internalization configuration for this widget
*/
public $i18n = [];
/**
* #inheritdoc
*/
public $pluginName = 'fileinput';
/**
* #var array the list of inbuilt themes
*/
private static $_themes = ['fa', 'gly'];
/**
* #var array initialize the FileInput widget
*/
public function init()
{
parent::init();
$this->_msgCat = 'fileinput';
$this->initI18N(__DIR__);
$this->initLanguage();
$this->registerAssets();
if ($this->pluginLoading) {
Html::addCssClass($this->options, 'file-loading');
}
$input = $this->getInput('fileInput');
$script = 'document.getElementById("' . $this->options['id'] . '").className.replace(/\bfile-loading\b/,"");';
if ($this->showMessage) {
$validation = ArrayHelper::getValue($this->pluginOptions, 'showPreview', true) ?
Yii::t('fileinput', 'file preview and multiple file upload') :
Yii::t('fileinput', 'multiple file upload');
$message = '<strong>' . Yii::t('fileinput', 'Note:') . '</strong> ' .
Yii::t(
'fileinput',
'Your browser does not support {validation}. Try an alternative or more recent browser to access these features.',
['validation' => $validation]
);
$content = Html::tag('div', $message, $this->messageOptions) . "<script>{$script};</script>";
$input .= "\n" . $this->validateIE($content);
}
echo $input;
}
/**
* Validates and returns content based on IE browser version validation
*
* #param string $content
* #param string $validation
*
* #return string
*/
protected function validateIE($content, $validation = 'lt IE 10')
{
return "<!--[if {$validation}]><br>{$content}<![endif]-->";
}
/**
* Registers the asset bundle and locale
*/
public function registerAssetBundle()
{
$view = $this->getView();
if ($this->resizeImages) {
CanvasBlobAsset::register($view);
$this->pluginOptions['resizeImage'] = true;
}
$theme = ArrayHelper::getValue($this->pluginOptions, 'theme');
if (!empty($theme) && in_array($theme, self::$_themes)) {
FileInputThemeAsset::register($view)->addTheme($theme);
}
if ($this->sortThumbs) {
SortableAsset::register($view);
}
if ($this->purifyHtml) {
DomPurifyAsset::register($view);
$this->pluginOptions['purifyHtml'] = true;
}
FileInputAsset::register($view)->addLanguage($this->language, '', 'js/locales');
}
/**
* Registers the needed assets
*/
public function registerAssets()
{
$this->registerAssetBundle();
$this->registerPlugin($this->pluginName);
}
}
it seems you are using a custom input widget, which uploads to a different url (/uploads). you didn't show the code for this specific /uploads action.
need more information.
btw, "<" in JSON looks like you are returning HTML instead of json. maybe you are throwing an exception. check it in your runtime/logs.

Uploading images with symfony. The image is not saved in the correct path

I am new at Symfony. I have been trying to create a reusable form and upload an image with it. The problem is that the image it is not saved in the path i have given. I dont know what i am doing wrong. I would really appreciate any suggestion.
Entity
<?php
namespace test\TestBundle\Entity\media;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\validator\Constraints as Assert;
/**
* Media
*#ORM\Entity
* #ORM\Table(name="upload")
* #ORM\HasLifecycleCallbacks
*/
class Media
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name",type="string",length=255)
* #Assert\NotBlank
*/
public $name;
/**
* #ORM\Column(name="path",type="string",length=255, nullable=true)
*/
public $path;
public $file;
/**
* #ORM\PostLoad()
*/
public function postLoad()
{
$this->updateAt = new \DateTime();
}
public function getUploadRootDir()
{
return __dir__.'/../../../../web/uploads';
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getAssetPath()
{
return 'uploads/'.$this->path;
}
/**
* #ORM\Prepersist()
* #ORM\Preupdate()
*/
public function preUpload()
{
$this->tempFile = $this->getAbsolutePath();
$this->oldFile = $this->getPath();
$this->updateAt = new \DateTime();
if (null !== $this->file)
$this->path = sha1(uniqid(mt_rand(),true)).'.'.$this->file->guessExtension();
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null !== $this->file) {
$this->file->move($this->getUploadRootDir(),$this->path);
unset($this->file);
if ($this->oldFile != null) unlink($this->tempFile);
}
}
/**
* #ORM\PreRemove()
*/
public function preRemoveUpload()
{
$this->tempFile = $this->getAbsolutePath();
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if (file_exists($this->tempFile)) unlink($this->tempFile);
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function getPath()
{
return $this->path;
}
public function getName()
{
var_dump($this->name);
return $this->name;
}
}
Controller
namespace test\TestBundle\Controller\media;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use test\TestBundle\Entity\media\Media;
use test\TestBundle\Form\media\MediaType;
/**
* media\Media controller.
*
* #Route("/img")
*/
class MediaController extends Controller
{
/**
* Lists all media\Media entities.
*
* #Route("/", name="img")
* #Method("GET")
* #Template()
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('testTestBundle:media\Media')->findAll();
return array(
'entities' => $entities,
);
}
/**
* Creates a new media\Media entity.
*
* #Route("/", name="img_create")
* #Method("POST")
* #Template("testTestBundle:media\Media:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Media();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('img_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a form to create a media\Media entity.
*
* #param Media $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Media $entity)
{
$form = $this->createForm(new MediaType(), $entity, array(
'action' => $this->generateUrl('img_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new media\Media entity.
*
* #Route("/new", name="img_new")
* #Method("GET")
* #Template()
*/
public function newAction()
{
$entity = new Media();
$form = $this->createCreateForm($entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Finds and displays a media\Media entity.
*
* #Route("/{id}", name="img_show")
* #Method("GET")
* #Template()
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('testTestBundle:media\Media')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find media\Media entity.');
}
$deleteForm = $this->createDeleteForm($id);
return array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
);
}
/**
* Displays a form to edit an existing media\Media entity.
*
* #Route("/{id}/edit", name="img_edit")
* #Method("GET")
* #Template()
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('testTestBundle:media\Media')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find media\Media entity.');
}
$editForm = $this->createEditForm($entity);
$deleteForm = $this->createDeleteForm($id);
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
/**
* Creates a form to edit a media\Media entity.
*
* #param Media $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Media $entity)
{
$form = $this->createForm(new MediaType(), $entity, array(
'action' => $this->generateUrl('img_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', 'submit', array('label' => 'Update'));
return $form;
}
/**
* Edits an existing media\Media entity.
*
* #Route("/{id}", name="img_update")
* #Method("PUT")
* #Template("testTestBundle:media\Media:edit.html.twig")
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('testTestBundle:media\Media')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find media\Media entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('img_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
/**
* Deletes a media\Media entity.
*
* #Route("/{id}", name="img_delete")
* #Method("DELETE")
*/
public function deleteAction(Request $request, $id)
{
$form = $this->createDeleteForm($id);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('testTestBundle:media\Media')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find media\Media entity.');
}
$em->remove($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('img'));
}
/**
* Creates a form to delete a media\Media entity by id.
*
* #param mixed $id The entity id
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm($id)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('img_delete', array('id' => $id)))
->setMethod('DELETE')
->add('submit', 'submit', array('label' => 'Delete'))
->getForm()
;
}
}
Form
namespace test\TestBundle\Form\media;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MediaType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file','file', array('required' => false))
->add('name')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'test\TestBundle\Entity\media\Media'
));
}
/**
* #return string
*/
public function getName()
{
return 'test_testbundle_media_media';
}
}
I you are playing with Symfony2 forms and file upload I'd not recommend doing it as it's described in official documentation.
Please take a look at https://github.com/dustin10/VichUploaderBundle, configure your upload, link entity and enjoy!
I think the documentation is a great example for basic file upload.
Try to update your entity like this :
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name",type="string",length=255)
* #Assert\NotBlank
*/
public $name;
/**
* #ORM\Column(name="path",type="string",length=255, nullable=true)
*/
public $path;
/**
* #Assert\File(maxSize="6000000")
*/
public $file;
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return File
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set path
*
* #param string $path
* #return File
*/
public function setPath($path)
{
$this->path = $path;
return $this;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
}
public function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function getUploadDir()
{
return 'uploads/documents/';
}
public function upload()
{
if (null === $this->getFile()){
return;
}
$this->getFile()->move(
$this->getUploadRootDir(),
$this->getFile()->getClientOriginalName()
);
$this->path = $this->getFile()->getClientOriginalName();
$this->file = null;
}
And in your controller, a simple upload action for GET and POST :
public function UploadAction()
{
$document = new Media();
$form = $this->createFormBuilder($document)
->add('file')
->getForm();
if ($this->getRequest()->isMethod('POST')) {
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$account = $em->getRepository('AccountingAccountBundle:Account')->findOneBy(array('id' => $accountId));
$document->setAccount($account);
$document->upload();
$em->persist($document);
$em->flush();
}
}
return array('form' => $form->createView());
}
If this example don't work on your server, maybe you have a problem with rights in your file system.
the problem was in the path directories, just needed one more directory return dir.'/../../../../../web/uploads'; like this :)
Most simplefied idea:
Create normal form in twig,and try to use/rebuilt to your own need trait below.
I used it in some simple uploads connected to entity, it's not a great code (no file validation etc. ) , but it can be a good start for you.
$location variable is configured if trait is in entity dir
user trait below to upload (
<?php
namespace AdminBundle\Entity;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
trait LinkFileTrait
{
private $location='/../../../web/media/link' ;
private $path=__DIR__;
public function checkDir(){
$id=$this->getId();
$fs=new Filesystem();
if(!$fs->exists($this->path.$this->location))
$fs->mkdir($this->path.$this->location);
$this->setImagePath($this->path.$this->location.'/'.$id.'');
if(!$fs->exists($this->getImagePath()))
$fs->mkdir($this->getImagePath());
}
public function getImages(){
$this->checkDir();
$finder = new Finder();
return $finder->files() ->in($this->getImagePath());
}
public function getRandomImage(){
$images=$this->getImages();
$images=iterator_to_array($images);
if(count($images)<1)
return null;
shuffle($images);
return $images[0];
}
public function UploadFile(UploadedFile $file){
$file->move($this->getImagePath().'/',$file->getClientOriginalName());
}
public function removeImage($file){
$this->checkDir();
$fs=new Filesystem();
if($fs->exists($this->getImagePath().'/'.$file))
$fs->remove($this->getImagePath().'/'.$file);
}
public function imageExists($image){
$this->checkDir();
$fs=new Filesystem();
return $fs->exists($this->getImagePath().'/'.$image);
}
public function getRelativePath($path){
$path=strtr($path,"\\","/");
$x=explode('../web/',$path);
return $x[1];
}
public function getImageName($path){
$path=strtr($path,"\\","/");
$x=explode('/',$path);
return $x[count($x)-1];
}
public function getFileName($path){
$x=explode('/',$path);
return $x[count($x)-1];
}
}
and in your controller
public function imagesAction(Link $link,Request $request)
{
$link->checkDir();
$images=$link->getImages();
if($request->getMethod()=='POST'){
$file=$request->files->all()['plik'];
$link->UploadFile($file);
}
return array('link'=>$link,'images'=>$images);
}

Resources