I created src/Model/Behavior/ModernTreeBehavior.php:
<?php
namespace Cake\ORM\Behavior;
use Cake\Datasource\EntityInterface;
use Cake\Datasource\Exception\RecordNotFoundException;
use Cake\Event\Event;
use Cake\ORM\Behavior;
use Cake\ORM\Entity;
use Cake\ORM\Query;
use InvalidArgumentException;
use RuntimeException;
class ModernTreeBehavior extends Behavior
{
/**
* Cached copy of the first column in a table's primary key.
*
* #var string
*/
protected $_primaryKey;
/**
* Default config
*
* These are merged with user-provided configuration when the behavior is used.
*
* #var array
*/
protected $_defaultConfig = [
'implementedFinders' => [
'children' => 'findChildren',
'treeList' => 'findTreeList'
],
'implementedMethods' => [
'childCount' => 'childCount',
'getLevel' => 'getLevel'
],
'parent' => 'parent_id',
'path' => 'path',
'scope' => null,
'level' => null
];
public function getLevel($entity)
{
$primaryKey = $this->_getPrimaryKey();
$id = $entity;
if ($entity instanceof EntityInterface) {
$id = $entity->get($primaryKey);
}
$config = $this->config();
$entity = $this->_table->find('all')
->select([$config['path']])
->where([$primaryKey => $id])
->first();
if ($entity === null) {
return false;
}
return substr_count($entity[$config['path']], '-') + 1;
}
/**
* Returns a single string value representing the primary key of the attached table
*
* #return string
*/
protected function _getPrimaryKey()
{
if (!$this->_primaryKey) {
$this->_primaryKey = (array)$this->_table->primaryKey();
$this->_primaryKey = $this->_primaryKey[0];
}
return $this->_primaryKey;
}
}
I used $this->addBehavior('ModernTree'); in CommentTables.php
and I got error Fatal error: Cannot redeclare class Cake\ORM\Behavior\ModernTreeBehavior in .../src/Model/Behavior/ModernTreeBehavior.php on line 0
But if I paste /src/Model/Behavior/ModernTreeBehavior.php into built-in file TreeBehavior.php and load TreeBehavior.php, everything so goods.
Can you tell me the reason?
The namespace declaration of your class is wrong, it should be:
namespace App\Model\Behavior;
Related
I am working on a Laravel project. I ran these commands and successfully created notifications table.
php artisan notifications:table
php artisan migrate
All of the things were going perfectly. Later on I created a Model name "NotificationsForAdmin" with migration named "notifications_for_admin", then later on I drooped this table. Now when I am trying to generate some notifications then it is showing me this error, I dont know whats going on I have notifications table in database that is needed for laravel notifications with perfect schema. the error is :
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'followup.notification_for_admins' doesn't exist (SQL: select * from `notification_for_admins` where `notification_for_admins`.`user_id` = 2 and `notification_for_admins`.`user_id` is not null)
My notifications is :
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use App\User;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Messages\MailMessage;
use App\Events\NewEmailReceivedEvent;
use Auth;
class NewEmailReceived extends Notification
{
use Queueable;
public $sender_id, $receiver_id, $sender_name, $receiver_name, $sender_type, $receiver_type, $type, $recipient, $from_email, $subject, $message, $image, $receiver_image, $attachments, $sizesOfAttachments, $originalFileNames, $thread_id, $id_of_email;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($sender_id, $receiver_id, $sender_name, $receiver_name, $sender_type, $receiver_type, $type, $recipient, $from_email, $subject, $message, $image, $receiver_image, $attachments, $sizesOfAttachments, $originalFileNames, $thread_id, $id_of_email)
{
$this->sender_id = $sender_id;
$this->receiver_id = $receiver_id;
$this->sender_name = $sender_name;
$this->receiver_name = $receiver_name;
$this->sender_type = $sender_type;
$this->receiver_type = $receiver_type;
$this->type = $type;
$this->recipient = $recipient;
$this->from_email = $from_email;
$this->subject = $subject;
$this->message = $message;
$this->image = $image;
$this->receiver_image = $receiver_image;
$this->attachments = $attachments;
$this->sizesOfAttachments = $sizesOfAttachments;
$this->originalFileNames = $originalFileNames;
$this->thread_id = $thread_id;
$this->id_of_email = $id_of_email;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
$notifications = Auth::user()->notifications;
if ($notifications[7]->shown == 1) {
return ['mail', 'database'];
}
else{
return ['database'];
}
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
return [
'sender_id' => $this->sender_id,
'receiver_id' => $this->receiver_id,
'sender_name' => $this->sender_name,
'receiver_name' => $this->receiver_name,
'sender_type' => $this->sender_type,
'receiver_type' => $this->receiver_type,
'type' => $this->type,
'recipient' => $this->recipient,
'from_email' => $this->from_email,
'subject' => $this->subject,
'message' => $this->message,
'image' => $this->image,
'receiver_image' => $this->receiver_image,
'attachments' => $this->attachments,
'sizesOfAttachments' => $this->sizesOfAttachments,
'originalFileNames' => $this->originalFileNames,
'thread_id' => $this->thread_id,
'id_of_email' => $this->id_of_email,
];
event(new NewEmailReceivedEvent($NewEmailReceivedRequest));
return $NewEmailReceivedRequest;
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject("New email from ".$this->sender_type)
->greeting('Hello!')
->markdown('mails.NewEmailReceived' , ['recipient_name' => $this->receiver_name , 'subject' => $this->subject , 'mailMessage' => str_limit($this->message, 50) , 'avatar' => $this->image]);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
I shall be very thankfull if someone could help me on this.
It seems your notifications relation on your User object still references NotificationsForAdmin.
If you do not specify the table for a model, the table is automatically generated as a snake_case string of the model name. In the case of NotificationsForAdmin this becomes notification_for_admins.
Add the public property $table to your NotificationsForAdmin with the name of the table where your notifications are stored as the value. This should fix your problem.
I am trying to retrieve data from the database by user_id. My view shows this error : Trying to get property of non-object. dd() return null.
This is my Controller :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use App\Complain;
use App\Feedback;
use App\Item;
use Illuminate\Support\Facades\Redirect;
use Session;
use Auth;
class ProfileController extends Controller
{
public function profile($id){
$complain = Complain::find($id);
dd($complain);
return view('user.profile')->with(['complains' => User::find($id)->complains]);
}
}
This is my User Model :
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'surname', 'regnumber', 'course', 'department', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function complains()
{
return $this->hasMany('App\Complain');
}
}
This is my Complain Model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Complain extends Model
{
protected $fillable = [
'user_id', 'title', 'body', 'name', 'regnumber'
];
public function user(){
return $this->belongsTo('App\User');
}
}
This is my view :
#foreach($complains as $complain)
<div>
<h3 class="operator-complain-title">Title: </h3>
<p>{{ $complain->title }}</p>
<h3 class="operator-complain-title">Complain:</h3>
<p>{{ $complain->body }}</p>
</div>
<hr>
#endforeach
The user_id is a foreign key. How do I successfully show complains(data) based on the user_id?
This is my users table:
id | name | email | password
7 John email password
This is my complains table :
id | user_id | title | body
5 7 complain 1 Complain 1
Anyone with ideas please share.
As I understand You want to get complains by user $id.
So doing Complain::find($id) will not return user's complain, cuz find gets by id field.
But You want to get complains by user_id field.
So for that case: Complain::whereUserId($id)->get()
Check this one (recommended when You're going to show user's data and it's complains):
public function profile(Request $request, $id){
$User = User::with(['complains'])->find($id);
if(!$User) return abort(404, 'User with id:'.$id.' not found');
return view('user.profile')->with(['user' => $User, 'complains' => $User->complains]);
}
or this one (if You're going to show complains only):
public function profile(Request $request, $id){
$complains = Complain::whereUserId($id)->get();
if(!$complains) return abort(404, 'No complains for user (id:'.$id.') found');
return view('user.profile')->with(['complains' => $complains]);
}
In case of $id is name of user:
public function profile(Request $request, $name){
$User = User::with(['complains'])->whereName($name)->first();
if(!$User) return abort(404, 'User with name:'.$name.' not found');
return view('user.profile')->with(['user' => $User, 'complains' => $User->complains]);
}
You would try to check first if the object is null or empty before trying to consume it like
<?php
$var = 0;
// Evaluates to true because $var is empty
if (empty($var)) {
echo '$var is either 0, empty, or not set at all';
}
// Evaluates as true because $var is set
if (isset($var)) {
echo '$var is set even though it is empty';
}
?>
public function profile($id)
should be
public function profile(Request $request)
And on Eloquent
$complain = Complain::find($request->id);
Or get query from segment. Example domain/id/ = id from slug number 1
$complain = Complain::find($request->segment(1));
I'm using yii2-advanced. I've several table :
tb_user:(iduser(PK),username),
tb_profile:(id,iduser(FK)),
tb_status:(id,iduser(FK))
My question is how can i insert iduser(PK) from tb_user to iduser(FK) on tb_profile and tb_status after i push the signup button.
For a while i think i must to do some modification of bevahiours() function on User model and i found some error, or adding trigger syntax on the table ? (i think this is not a good ways).
Is there anyone who can help me, how to solve my problem ?
this is the User model before the modification :
<?php
namespace common\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
/**
* #inheritdoc
*/
public static function tableName()
{
return '{{%user}}';
}
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'timestamp' => [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'created_at',
ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_at',
],
'value' => function () {return date('Y-m-d h:m:s');},
],
];
}
/**
* #inheritdoc
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
/**
* #inheritdoc
*/
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
}
/**
* #inheritdoc
*/
public function getId()
{
return $this->getPrimaryKey();
}
}
?>
The Controller :
public function actionSignup()
{
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->render('signup', [
'model' => $model,
]);
}
I had similar situation in one of my project where i had 2 tables like user,user_image where user_id was foreign key to add the path.
For those kind of situation you can use either of following approach
1.Insert record in both table on click of signup button. You will have to write update action accordingly.
$user = new User();
$user->name = "John"
$user->email = "John#gmail.com"
//Add if any other fields in table
$user->save(); //save the record
$user_image = new UserImage();
$user_image->user_id = $user->id;
$user_image->image = "image path"
//Add any other images here
$user_image->save();//save the record
2.You can also call create action of UserImage and do the same. If you use this approach than you might also need to use any other unique column to find the id of that user and use it to insert new record,for example in my table email is unique column so i can write following code in UserImage and get the id
$user = User::findOne(['email' => 'john#gmail.com']);//this will return whole row
$user_image->user_id = $user->id;
$user_image->image = "image path"
//Add any other images here
$user_image->save();//save the record
And that way you can use the code as per it suits your need
Thank you
In controller i have:
public function actionGetItems()
{
$model = new \app\models\WarehouseItems;
$items = $model->find()->with(['user'])->asArray()->all();
return $items;
}
In WarehouseItem model i have standard (created by gii) relation declaration:
public function getUser()
{
return $this->hasOne('\dektrium\user\models\User', ['user_id' => 'user_id']);
}
How can i control which column data do i get from "user" relation? I currently get all columns which is not good as that data is being sent to Angular in JSON format.
Right now i have to loop trough $items and filer out all columns i dont want to send.
You should simply modify the relation query like this :
$items = \app\models\WarehouseItems::find()->with([
'user' => function ($query) {
$query->select('id, col1, col2');
}
])->asArray()->all();
Read more : http://www.yiiframework.com/doc-2.0/yii-db-activequerytrait.html#with()-detail
Your code should go this way.
public function actionGetItems()
{
$items = \app\models\WarehouseItems::find()
->joinWith([
/*
*You need to use alias and then must select index key from parent table
*and foreign key from child table else your query will give an error as
*undefined index **relation_key**
*/
'user as u' => function($query){
$query->select(['u.user_id', 'u.col1', 'u.col2']);
}
])
->asArray()
->all();
return $items;
}
Inside WarehouseItem model
/**
* #return ActiveQuery
*/
public function getUser()
{
$query = User::find()
->select(['id', 'col1', 'col2'])
->where([
'id' => $this->user_id,
]);
/**
* Default hasOne, setup multiple for hasMany
* $query->multiple = true;
*/
return $query;
}
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']); ?>