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
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
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);
}
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!
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.
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);
}