Yii2 Custom Class - namespace error - namespaces

I am trying to create a custom class that can be called to convert dates and times for MySQL.
I am using the Yii2 Basic template
I have created a folder and a file in components called Convert.php
<?
namespace app\components;
use Yii;
class Convert
{
const DATE_FORMAT = 'php:Y-m-d';
const DATETIME_FORMAT = 'php:Y-m-d H:i:s';
const TIME_FORMAT = 'php:H:i:s';
public static function toMysql($dateStr, $type='date', $format = null) {
if ($type === 'datetime') {
$fmt = ($format == null) ? self::DATETIME_FORMAT : $format;
}
elseif ($type === 'time') {
$fmt = ($format == null) ? self::TIME_FORMAT : $format;
}
else {
$fmt = ($format == null) ? self::DATE_FORMAT : $format;
}
return \Yii::$app->formatter->asDate($dateStr, $fmt);
}
}
?>
I then try and call this method in my controller
use app\components\Convert;
...
public function actionCreate()
{
...
$model->date_of_birth = Convert::toMysql($model->date_of_birth);
...
}
However I am getting the following error
Unable to find 'app\components\Convert' in file: /var/www/html/portal/components/Convert.php. Namespace missing?
I am probably missing something simple, but I cannot see it.
Thanks for your help.
Liam
From the comments, I have found that the error was a simple mistake, the opening tag should have been
<?php

This error simply means php cannot find the namespace in this file, and since the namespace seems to be correct, it is probably a php opening tag error.
Depending on your server php configuration, short open tags could be disabled, you should always use <?php.

You need to extend base Component from Yii2:
<?php
namespace app\components;
use yii\base\Component;
use Yii;
class Convert extends Component
{
const DATE_FORMAT = 'php:Y-m-d';
And then put in config/web.php
'components' => [
'convert' => [
'class' => 'app\components\Convert',
],
]
and access it as
$model->date_of_birth = Yii::$app->convert->toMysql($model->date_of_birth);

Related

Return URL image in Laravel API

I need to return URL path and name image from database.
This my call method to get data from database:
public function index(){
$rav=Rav::select('id','image','nameravs')->get('image');
return $this->sendResponse($rav->toArray(),'rav show is succesfuly');
}
Output data it look like this:
{
"id": 88,
"image": "1579781806.png",
"nameravs": "asdad"
},
But I want to return image with path URL like this:
"image": http://127.0.0.1:8000/images_ravs/1579781806.png
You can use Eloquent Accessor
add the image url attribute in Rav.php Model like below. then you can access it any place.
public function getImageUrlAttribute($value)
{
return env('APP_URL'). '/images_ravs/' . $this->image;
}
And don't forget to Add Appends property inside the Model
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = ['image_url'];
then you can access it like below.
$rav->image_url
Define An Accessor in your model like this example :
public function getImageAttribute($value)
{
return env('APP_URL') . Storage::url($value);
}
Try this:
public function index(){
$rav = Rav::select('id','image','nameravs')->get('image');
return $this->sendResponse(
[
'id' => $rav->id,
'image' => URL::to('/').'/images_ravs/'.rav->image,
'nameravs' => $rev->nameravs
],'rav show is succesfuly');
}
You can use selectRaw or select with DB::raw and just concat that path as a prepended string infront of your image column in your query:
Rav::select(DB::raw("id, nameravs, CONCAT('/images_ravs/', image) as image"))->get()->toArray();
No need to include the URL (unless for some reason you have some type of CDN in front of it) in which case you can just escape the string and add it if necessary.
I would do something like this: Try to use as many od Laravel's built-in functions as possible. In most cases you don't need to reinvent the wheel.
public function index(){
$ravs = Rav::select('id','image','nameravs')->get();
$results = [];
foreach($ravs as $rav){
$rav->image = env('APP_URL') . '/images_ravs/' . $rav->image;
array_push($results, $rav);
}
return response()->json($results);
}
In the Model you can create getAttribute:
public function getImageAttribute()
{
return $this->attributes['image'] ? URL::to('/uploads/' . $this->attributes['image']) : null;
}
Or you can create custom casts file:
protected $casts = [
'image' => ImageCast::class,
'created_at' => 'datetime',
'updated_at' => 'datetime',
];

Base Table not found on unique value validation in MongoDB with laravel

I'm using laravel 5.3 with jenssegers/laravel-mongodb package for managing mongodb connections.
I want to check every time a user send a request to register a website in my controller if it's unique then let the user to register his/her website domain.
I wrote below code for validation but What I get in result is :
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'iranad.seat' doesn't exist (SQL: select count(*) as aggregate from `seat` where `domain` = order.org)
my controller code :
public function store(Request $request) {
$seat = new Seat();
$validator = Validator::make($request->all(), [
'domain' => 'required|regex:/^([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/|unique:seat', //validating user is entering correct url like : iranad.ir
'category' => 'required',
]);
if ($validator->fails()) {
return response()->json($validator->messages(), 400);
} else {
try {
$statusCode = 200;
$seat->user_id = Auth::user()->id;
$seat->url = $request->input('domain');
$seat->cats = $request->input('category');
$seat->filter = [];
if($request->input('category') == 'all') {
$obj['cats'] = 'false';
$seat->target = $obj;
} else {
$obj['cats'] = 'true';
$seat->target = $obj;
}
$seat->status = 'Waiting';
$seat->save();
} catch (\Exception $e) {
$statusCode = 400;
} finally {
$response = \Response::json($seat, $statusCode);
return $response;
}
}
}
My Seat Model :
namespace App;
use Moloquent;
use Carbon\Carbon;
class Seat extends Moloquent {
public function getCreatedAtAttribute($value) {
return Carbon::createFromTimestamp(strtotime($value))
->timezone('Asia/Tehran')
->toDateTimeString();
}
}
Obviously The validator is checking if domain is unique in mysql tables which causes this error, How can I change my validation process to check mongodb instead of mysql ?
I solved the problem, The solution is that you should add Moloquent to your model and define database connection :
namespace App\Models;
use Moloquent;
use Carbon\Carbon;
class Seat extends Moloquent
{
protected $collection = 'seat';
protected $connection = 'mongodb';
}

Yii2 POST image to model in API without Yii2 Naming convention

I'm creating an endpoint for a mobile application to send a image to the server. I'm posting the image with the POSTMAN extension for chrome. The image is in the $_FILES variable, and named image. How can I load this image into a model, or the UploadedFile class? The $model->load(Yii::$app->request->post()) line does not correctly load the file, as it is not in Yii2's naming convention for forms.
It's currently returning:
{
"success": false,
"message": "Required parameter 'image' is not set."
}
Code
models\Image.php
<?php
namespace api\modules\v1\models;
use yii\base\Model;
use yii\web\UploadedFile;
class Image extends Model
{
/**
* #var UploadedFile
*/
public $image;
public function rules()
{
return [
[['image'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
public function upload()
{
$path = dirname(dirname(__FILE__)) . '/temp/';
if ($this->validate()) {
$this->image->saveAs($path . $this->image->baseName . '.' . $this->image->extension);
return true;
} else {
die(var_dump($this->errors));
return false;
}
}
}
controllers\DefaultController.php
<?php
namespace api\modules\v1\controllers;
use api\modules\v1\models\Image;
use yii\web\Controller;
use yii\web\UploadedFile;
use Yii;
class DefaultController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$model = new Image();
if (Yii::$app->request->isPost) {
if($model->load(Yii::$app->request->post()))
{
$model->image = UploadedFile::getInstance($model, 'image');
if ($model->upload()) {
// file is uploaded successfully
return ['success' => true, 'message' => 'File saved.'];
}
else return ['success' => false, 'message' => 'Could not save file.'];
}
else return ['success' => false, 'message' => 'Required parameter \'image\' is not set.'];
}
else return ['success' => false, 'message' => 'Not a POST request.'];
}
}
Postman
Your problem seems to be the name you are using to send the image file. Usually Yii2 uses names for form attributes like "ModelName[attributeName]" and you are sending your image file with the name "image"
There are 2 ways of fixing this:
Change the name you use to send your image file to follow the same naming conveniton. However you don't seem to want that.
Use getInstanceByName('image') method instead of getInstance($model, 'image')
The problem come here
When you send files via api they are not sent asynchronously. If you check
echo '<pre>';
print_r($_FILES); //returns nothing
print_r($_POST["image"]); //returns something
echo '</pre>';
die;
One reason is that your controller extendsyii\web\controller which is not used by rest apis, extend yii\rest\controller
The other way to go about this is by using javascript formData when sending the post request
This is a way i handled a previous ajax post of an image probably itll give you a guideline
The form
<?php $form = ActiveForm::begin(['options' => ['enctype' =>
'multipart/form-data','id'=>'slider_form']]); ?> //dont forget enctype
<?= $form->field($model, 'file')->fileInput() ?>
Then on the ajax post
var formData = new FormData($('form#slider_form')[0].files);
$.post(
href, //serialize Yii2 form
{other atributes ,formData:formData}
)
Then on the controller simply access via
$model->file =$_FILES["TblSlider"]; //here this depends on your form attributes check with var_dump($_FILES)
$file_tmp = $_FILES["TblSlider"]["tmp_name"]["file"];
$file_ext = pathinfo($_FILES['TblSlider']['name']["file"], PATHINFO_EXTENSION);
if(!empty($model->file)){
$filename = strtotime(date("Y-m-d h:m:s")).".".$file_ext;
move_uploaded_file($file_tmp, "../uploads/siteimages/slider/".$filename);
///move_uploaded_file($file_tmp, Yii::getAlias("#uploads/siteimages/slider/").$filename);
$model->image = $filename;
}
I hope this helps

class not found even when it exits on Yii2

I'm making my first application using Yii and I have the next code:
public function actionCreate()
{
$model = new User();
$singUp = new \frontend\models\SingupForm;
if ($singUp->load(Yii::$app->request->post()) && $singUp->save()) {
$model = ModelName::findOne(['id' => $singUP->id]);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
return $this->render('create', [
'model' => $model,
'singUp' => $singUp
]);
}
}
And I'm having the next error message when I try to go to that method:
Class 'frontend\models\SingupForm' not found
But I have the file saved on the directory as it is showed in the screenshot I attached. Additionally I added all the models folder of the Frontend on the controller I am using:
use Yii;
use \frontend\models;
use common\models\User;
use backend\models\search\UserSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use common\models\PermissionHelpers;
So I don't know what I'm doing wrong. Please help
Screenshot
There is a typo in your code.
Please Change frontend\models\SingupForm to frontend\models\SignupForm.

How to access configs from autoloaded config files in a layout / view script in Zend Framework 2?

I would like / have to manage some settings in ZF1 style and provide the view with the infomation about the current environment.
/config/application.config.php
return array(
...
'module_listener_options' => array(
...
'config_glob_paths' => array('config/autoload/{,*.}{global,local}.php')
)
);
/config/autoload/env.local.php
return array(
// allowed values: development, staging, live
'environment' => 'development'
);
In a common view script I can do it over the controller, since the controllers have access to the Service Manager and so to all configs I need:
class MyController extends AbstractActionController {
public function myAction() {
return new ViewModel(array(
'currentEnvironment' => $this->getServiceLocator()->get('Config')['environment'],
));
}
}
Is it also possible to get the configs in a common view directly?
How can I access the configs in a layout view script (/module/Application/view/layout/layout.phtml)?
(My implementation/interpretation of) Crisp's suggestion:
Config view helper
<?php
namespace MyNamespace\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\View\HelperPluginManager as ServiceManager;
class Config extends AbstractHelper {
protected $serviceManager;
public function __construct(ServiceManager $serviceManager) {
$this->serviceManager = $serviceManager;
}
public function __invoke() {
$config = $this->serviceManager->getServiceLocator()->get('Config');
return $config;
}
}
Application Module class
public function getViewHelperConfig() {
return array(
'factories' => array(
'config' => function($serviceManager) {
$helper = new \MyNamespace\View\Helper\Config($serviceManager);
return $helper;
},
)
);
}
Layout view script
// do whatever you want with $this->config()['environment'], e.g.
<?php
if ($this->config()['environment'] == 'live') {
echo $this->partial('partials/partial-foo.phtml');;
}
?>
My implementation/interpretation of Sam's solution hint for the concret goal (to permit displaying the web analytics JS within the dev/staging environment):
DisplayAnalytics view helper
<?php
namespace MyNamespace\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\View\HelperPluginManager as ServiceManager;
class DisplayAnalytics extends AbstractHelper {
protected $serviceManager;
public function __construct(ServiceManager $serviceManager) {
$this->serviceManager = $serviceManager;
}
public function __invoke() {
if ($this->serviceManager->getServiceLocator()->get('Config')['environment'] == 'development') {
$return = $this->view->render('partials/partial-bar.phtml');
}
return $return;
}
}
Application Module class
public function getViewHelperConfig() {
return array(
'factories' => array(
'displayAnalytics' => function($serviceManager) {
$helper = new \MyNamespace\View\Helper\DisplayAnalytics($serviceManager);
return $helper;
}
)
);
}
Layout view script
<?php echo $this->displayAnalytics(); ?>
So this solution becomes more flexible:
/config/application.config.php
return array(
...
'module_listener_options' => array(
...
'config_glob_paths' => array('config/autoload/{,*.}{global,local}.php')
)
);
/config/autoload/whatever.local.php and /config/autoload/whatever.global.php
return array(
// allowed values: development, staging, live
'environment' => 'development'
);
ContentForEnvironment view helper
<?php
namespace MyNamespace\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\View\HelperPluginManager as ServiceManager;
class ContentForEnvironment extends AbstractHelper {
protected $serviceManager;
public function __construct(ServiceManager $serviceManager) {
$this->serviceManager = $serviceManager;
}
/**
* Returns rendered partial $partial,
* IF the current environment IS IN $whiteList AND NOT IN $blackList,
* ELSE NULL.
* Usage examples:
* Partial for every environment (equivalent to echo $this->view->render($partial)):
* echo $this->contentForEnvironment('path/to/partial.phtml');
* Partial for 'live' environment only:
* echo $this->contentForEnvironment('path/to/partial.phtml', ['live']);
* Partial for every environment except 'development':
* echo $this->contentForEnvironment('path/to/partial.phtml', [], ['development', 'staging']);
* #param string $partial
* #param array $whiteList
* #param array $blackList optional
* #return string rendered partial $partial or NULL.
*/
public function __invoke($partial, array $whiteList, array $blackList = []) {
$currentEnvironment = $this->serviceManager->getServiceLocator()->get('Config')['environment'];
$content = null;
if (!empty($whiteList)) {
$content = in_array($currentEnvironment, $whiteList) && !in_array($currentEnvironment, $blackList)
? $this->view->render($partial)
: null
;
} else {
$content = !in_array($currentEnvironment, $blackList)
? $this->view->render($partial)
: null
;
}
return $content;
}
}
Application Module class
public function getViewHelperConfig() {
return array(
'factories' => array(
'contentForEnvironment' => function($serviceManager) {
$helper = new \MyNamespace\View\Helper\ContentForEnvironment($serviceManager);
return $helper;
}
)
);
}
Layout view script
<?php echo $this->contentForEnvironment('path/to/partial.phtml', [], ['development', 'staging']); ?>